various: format with clang-format
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: Ib9abc9d2dcd036d3680c5aa3dc919bfa6a6a6964
This commit is contained in:
parent
63a9eddc49
commit
98fd1bfc52
12 changed files with 1923 additions and 1819 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#include "ir_gen.h"
|
||||
#include <algorithm>
|
||||
#include <stack>
|
||||
#include <unordered_map>
|
||||
#include <algorithm>
|
||||
|
||||
namespace nix_irc {
|
||||
|
||||
|
|
@ -31,7 +31,8 @@ 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);
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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,94 +115,119 @@ 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});
|
||||
|
||||
|
|
@ -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});
|
||||
|
|
@ -870,7 +983,8 @@ public:
|
|||
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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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 "";
|
||||
|
|
@ -108,4 +111,4 @@ std::string normalize_path(const std::string& path) {
|
|||
return fs::absolute(p).string();
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace nix_irc
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -198,9 +236,7 @@ struct Deserializer::Impl {
|
|||
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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
@ -43,24 +35,18 @@ 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();
|
||||
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();
|
||||
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;
|
||||
|
|
@ -93,9 +75,7 @@ static void prim_compileNix(EvalState &state, const PosIdx pos, Value **args,
|
|||
evaluator.eval_to_nix(ir, v);
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
state.error<EvalError>("IR compilation failed: %s", e.what())
|
||||
.atPos(pos)
|
||||
.debugThrow();
|
||||
state.error<EvalError>("IR compilation failed: %s", e.what()).atPos(pos).debugThrow();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -103,8 +83,7 @@ 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();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue