brewery
notashelf /
51305298ee988baf9f786406dad193b1ee310f28

nixir

public

Import-resolving Nix IR plugin

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

Commit 51305298ee98

tarball

NotAShelf <raf@notashelf.dev> · 2026-04-24 20:13 UTC

unverified1 files changed+62-17
irc/parser: fix list parsing and function application

Fixes bug where `concat [1 2 3] [4 5 6]` tried to apply integer 1
as a function.

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I6f373dd83bcac9e59286b0448472200b6a6a6964
diff --git a/src/irc/parser.cpp b/src/irc/parser.cppindex 8d92617..2bb31ed 100644--- a/src/irc/parser.cpp+++ b/src/irc/parser.cpp@@ -636,8 +636,9 @@ private:    void tokenize_ident() {     size_t start = pos;-    while (pos < input.size() && (isalnum(input[pos]) || input[pos] == '_' || input[pos] == '-' ||-                                  input[pos] == '+' || input[pos] == '.'))+    // Note: Don't include '.' here - it's used for selection (a.b.c)+    // URIs are handled separately by checking for '://' pattern+    while (pos < input.size() && (isalnum(input[pos]) || input[pos] == '_' || input[pos] == '-'))       pos++;     std::string ident = input.substr(start, pos - start); @@ -927,16 +928,25 @@ public:     std::shared_ptr<Node> left = parse_expr3();      while (true) {-      if (current().type == Token::LBRACKET) {-        advance();-        auto arg = parse_expr();-        expect(Token::RBRACKET);-        left = std::make_shared<Node>(AppNode(left, arg));-      } else if (current().type == Token::STRING) {+      if (current().type == Token::STRING) {         Token s = current();         advance();         auto arg = std::make_shared<Node>(ConstStringNode(s.value));         left = std::make_shared<Node>(AppNode(left, arg));+      } else if (current().type == Token::LPAREN) {+        // Function application with parenthesized argument: func (expr)+        advance();+        auto arg = parse_expr();+        expect(Token::RPAREN);+        left = std::make_shared<Node>(AppNode(left, arg));+      } else if (current().type == Token::IDENT || current().type == Token::INT ||+                 current().type == Token::FLOAT || current().type == Token::BOOL ||+                 current().type == Token::PATH || current().type == Token::LOOKUP_PATH ||+                 current().type == Token::URI || current().type == Token::LBRACKET) {+        // Juxtaposition application: f x+        // Parse the argument as a primary expression (which handles lists, etc.)+        auto arg = parse_expr3();+        left = std::make_shared<Node>(AppNode(left, arg));       } else {         break;       }@@ -969,6 +979,16 @@ public:       return expr;     } +    // Handle rec { ... } syntax+    if (consume(Token::REC)) {+      expect(Token::LBRACE);+      auto attrs = parse_attrs();+      if (auto* attrset = attrs->get_if<AttrsetNode>()) {+        attrset->recursive = true;+      }+      return attrs;+    }+     if (consume(Token::LBRACE)) {       return parse_attrs();     }@@ -1151,6 +1171,35 @@ public:     return std::make_shared<Node>(std::move(attrs));   } +  // Parse a list element: supports selections but NOT juxtaposition application+  // This prevents [1 2 3] from being parsed as ((1 2) 3)+  std::shared_ptr<Node> parse_list_element() {+    auto left = parse_expr3();++    // Handle selections (a.b.c)+    while (current().type == Token::DOT) {+      advance();+      Token name = current();+      if (name.type == Token::IDENT) {+        advance();+        auto attr = std::make_shared<Node>(ConstStringNode(name.value));+        left = std::make_shared<Node>(SelectNode(left, attr));+        continue;+      }+      break;+    }++    // Check for 'or' default value+    if (left->get_if<SelectNode>() && current().type == Token::IDENT && current().value == "or") {+      advance();+      auto default_expr = parse_expr3();+      auto* select = left->get_if<SelectNode>();+      select->default_expr = default_expr;+    }++    return left;+  }+   std::shared_ptr<Node> parse_list() {     std::vector<std::shared_ptr<Node>> elements; @@ -1158,18 +1207,14 @@ public:       return std::make_shared<Node>(ListNode(elements));     } -    while (current().type != Token::RBRACKET) {-      elements.push_back(parse_expr());-      if (!consume(Token::RBRACKET)) {-        // Elements are whitespace-separated in Nix, no comma required-        // But we'll continue parsing until we hit ]-      } else {-        // Found closing bracket-        return std::make_shared<Node>(ListNode(elements));+    while (current().type != Token::RBRACKET && current().type != Token::EOF_) {+      elements.push_back(parse_list_element());+      if (current().type == Token::RBRACKET) {+        break;       }     } -    // Unreachable, but for safety+    expect(Token::RBRACKET);     return std::make_shared<Node>(ListNode(elements));   }