clone
ssh://git@git.notashelf.dev:33/notashelf/nixir.gitCommit 3441853eefef
tarballunverified2 files changed+50-16
@@ -21,10 +21,6 @@ struct IREnvironment { explicit IREnvironment(IREnvironment* p = nullptr) : parent(p), with_attrs(nullptr) {} - IREnvironment* push() {- return new IREnvironment(this);- }- void bind(Value* val) { bindings.push_back(val); }@@ -104,7 +100,7 @@ struct Evaluator::Impl { thunk->blackholed = true; eval_node(thunk->expr, *v, thunk->env);- thunks.erase(it);+ thunks.erase(v); } void eval_node(const std::shared_ptr<Node>& node, Value& v, IREnvironment* env) {@@ -231,6 +227,8 @@ struct Evaluator::Impl { case BinaryOp::ADD: if (left->type() == nInt && right->type() == nInt) { v.mkInt((left->integer() + right->integer()).valueWrapping());+ } else if (left->type() == nString && right->type() == nString) {+ v.mkString(std::string(left->c_str()) + std::string(right->c_str())); } else { state.error<EvalError>("type error in addition").debugThrow(); }@@ -268,6 +266,8 @@ struct Evaluator::Impl { case BinaryOp::LT: if (left->type() == nInt && right->type() == nInt) { v.mkBool(left->integer() < right->integer());+ } else if (left->type() == nString && right->type() == nString) {+ v.mkBool(std::string(left->c_str()) < std::string(right->c_str())); } else { state.error<EvalError>("type error in comparison").debugThrow(); }@@ -275,6 +275,8 @@ struct Evaluator::Impl { case BinaryOp::GT: if (left->type() == nInt && right->type() == nInt) { v.mkBool(left->integer() > right->integer());+ } else if (left->type() == nString && right->type() == nString) {+ v.mkBool(std::string(left->c_str()) > std::string(right->c_str())); } else { state.error<EvalError>("type error in comparison").debugThrow(); }@@ -282,6 +284,8 @@ struct Evaluator::Impl { case BinaryOp::LE: if (left->type() == nInt && right->type() == nInt) { v.mkBool(left->integer() <= right->integer());+ } else if (left->type() == nString && right->type() == nString) {+ v.mkBool(std::string(left->c_str()) <= std::string(right->c_str())); } else { state.error<EvalError>("type error in comparison").debugThrow(); }@@ -289,16 +293,15 @@ struct Evaluator::Impl { case BinaryOp::GE: if (left->type() == nInt && right->type() == nInt) { v.mkBool(left->integer() >= right->integer());+ } else if (left->type() == nString && right->type() == nString) {+ v.mkBool(std::string(left->c_str()) >= std::string(right->c_str())); } else { state.error<EvalError>("type error in comparison").debugThrow(); } break; case BinaryOp::CONCAT:- if (left->type() == nString && right->type() == nString) {- v.mkString(std::string(left->c_str()) + std::string(right->c_str()));- } else {- state.error<EvalError>("type error in concatenation").debugThrow();- }+ // ++ is list concatenation in Nix; string concat uses ADD (+)+ state.error<EvalError>("list concatenation not yet implemented").debugThrow(); break; default: state.error<EvalError>("unknown binary operator").debugThrow();@@ -410,7 +413,9 @@ struct Evaluator::Impl { auto attr = obj->attrs()->get(sym); if (attr) {- v = *attr->value;+ Value* val = attr->value;+ force(val);+ v = *val; } else if (n->default_expr) { eval_node(*n->default_expr, v, env); } else {@@ -27,7 +27,10 @@ static std::string read_file(const std::string& path) { long size = ftell(f); fseek(f, 0, SEEK_SET); std::string content(size, '\0');- fread(content.data(), 1, size, f);+ if (fread(content.data(), 1, size, f) != static_cast<size_t>(size)) {+ fclose(f);+ throw std::runtime_error("Failed to read file: " + path);+ } fclose(f); return content; }@@ -761,7 +764,11 @@ public: } } - expect(Token::RBRACE);+ if (!consume(Token::RBRACE)) {+ // Not a lambda pattern, restore+ pos = saved_pos;+ return nullptr;+ } if (!consume(Token::COLON)) { // Not a lambda, restore@@ -817,6 +824,7 @@ public: // Create lambda auto lambda = LambdaNode(1, let_node); lambda.param_name = arg_name;+ lambda.strict_pattern = !has_ellipsis; return std::make_shared<Node>(std::move(lambda)); } @@ -842,13 +850,33 @@ public: i += 2; // Skip ${ int depth = 1; size_t expr_start = i;+ bool in_string = false;+ char string_quote = 0; while (i < raw.size() && depth > 0) {- if (raw[i] == '{') depth++;- else if (raw[i] == '}') depth--;+ if (!in_string) {+ if (raw[i] == '"' || raw[i] == '\'') {+ in_string = true;+ string_quote = raw[i];+ } else if (raw[i] == '{') {+ depth++;+ } else if (raw[i] == '}') {+ depth--;+ }+ } else {+ 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) {+ throw std::runtime_error("unterminated ${ in string interpolation");+ }+ // Parse the expression std::string expr_str = raw.substr(expr_start, i - expr_start); @@ -893,7 +921,8 @@ public: auto result = parts[0]; for (size_t j = 1; j < parts.size(); j++) {- result = std::make_shared<Node>(BinaryOpNode(BinaryOp::CONCAT, result, parts[j]));+ // Use ADD (+) for string concatenation; CONCAT (++) is Nix list concatenation+ result = std::make_shared<Node>(BinaryOpNode(BinaryOp::ADD, result, parts[j])); } return result;