brewery
notashelf /
3441853eefef2a3380fa4008e916bb70e83a4825

nixir

public

Import-resolving Nix IR plugin

Star0tarball
clone
ssh://git@git.notashelf.dev:33/notashelf/nixir.git

Commit 3441853eefef

tarball

NotAShelf <raf@notashelf.dev> · 2026-02-21 21:07 UTC

unverified2 files changed+50-16
various: fix string comparison, interpolation and ADD op. for strings

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Ice1bfb5682ab48a967dc16f1378e23ae6a6a6964
diff --git a/src/irc/evaluator.cpp b/src/irc/evaluator.cppindex 8aa64c7..977ea85 100644--- a/src/irc/evaluator.cpp+++ b/src/irc/evaluator.cpp@@ -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 {diff --git a/src/irc/parser.cpp b/src/irc/parser.cppindex 3ec6f86..8a47e2a 100644--- a/src/irc/parser.cpp+++ b/src/irc/parser.cpp@@ -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;