clone
ssh://git@git.notashelf.dev:33/notashelf/nixir.gitCommit f6481b3c0120
tarballunverified1 files changed+20-45
@@ -1352,45 +1352,22 @@ public: // Parse body auto body = parse_expr(); - // Desugar pattern to lambda with let bindings- // { a, b ? x }: body → arg: let a = arg.a; b = if arg ? a then arg.a else x; in body-- std::string arg_name = named_arg.value_or("_arg");- auto arg_var = std::make_shared<Node>(VarNode(0, arg_name));-- std::vector<std::pair<std::string, std::shared_ptr<Node>>> bindings;+ // Create LambdaPatternNode instead of desugaring+ auto pattern = LambdaPatternNode(body);+ pattern.allow_extra = has_ellipsis;+ pattern.at_binding = named_arg; + // Separate required and optional fields 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))));-+ PatternField pf(field.name, field.default_val); 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));- bindings.push_back({field.name, if_node});+ pattern.optional_fields.push_back(std::move(pf)); } else {- bindings.push_back({field.name, select});+ pattern.required_fields.push_back(std::move(pf)); } } - // If named pattern, also bind the argument name- if (named_arg) {- bindings.push_back({*named_arg, arg_var});- }-- // Create let expression- auto let = LetNode(body);- let.bindings = std::move(bindings);- auto let_node = std::make_shared<Node>(std::move(let));-- // 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));+ return std::make_shared<Node>(std::move(pattern)); } // Not a lambda@@ -1399,7 +1376,7 @@ public: } std::shared_ptr<Node> parse_string_interp(const std::string& raw) {- std::vector<std::shared_ptr<Node>> parts;+ std::vector<StringPart> parts; size_t i = 0; std::string current_str; @@ -1407,7 +1384,7 @@ public: if (raw[i] == '$' && i + 1 < raw.size() && raw[i + 1] == '{') { // Save current string part if any if (!current_str.empty()) {- parts.push_back(std::make_shared<Node>(ConstStringNode(current_str)));+ parts.push_back(StringPart::make_literal(current_str)); current_str.clear(); } @@ -1463,10 +1440,8 @@ public: tokens = saved_tokens; pos = saved_pos; - // Convert to string using toString builtin- auto to_string = std::make_shared<Node>(VarNode(0, "toString"));- auto str_expr = std::make_shared<Node>(AppNode(to_string, expr));- parts.push_back(str_expr);+ // Add expression part (will be coerced to string during evaluation)+ parts.push_back(StringPart::make_expr(expr)); i++; // Skip } } else {@@ -1477,21 +1452,21 @@ public: // Add remaining string part if (!current_str.empty()) {- parts.push_back(std::make_shared<Node>(ConstStringNode(current_str)));+ parts.push_back(StringPart::make_literal(current_str)); } - // Build concatenation tree+ // Return StringInterpolationNode if (parts.empty()) { return std::make_shared<Node>(ConstStringNode("")); } - auto result = parts[0];- for (size_t j = 1; j < parts.size(); j++) {- // Use ADD (+) for string concatenation; CONCAT (++) is Nix list concatenation- result = std::make_shared<Node>(BinaryOpNode(BinaryOp::ADD, result, parts[j]));+ // If only one literal part, return it directly as ConstStringNode+ if (parts.size() == 1 && parts[0].type == StringPart::Type::LITERAL) {+ return std::make_shared<Node>(ConstStringNode(parts[0].literal)); } - return result;+ // Otherwise return StringInterpolationNode+ return std::make_shared<Node>(StringInterpolationNode(std::move(parts))); } };