irc/parser: use explicit IR nodes for patterns and interpolation
Replaces lambda pattern desugaring with direct `LambdaPatternNode` generation, which: - Separates required and optional fields in pattern structure - Preserves @-binding and ellipsis information in IR - Remove like 50 lines of Let-binding desugaring logic and replace string interpolation concatenation tree with `StringInterpolationNode` to: - Use `StringPart::make_literal/make_expr` for cleaner representation - Optimize single-literal strings to `ConstStringNode` - Remove `toString` builtin wrapper generation Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I7d3fa038f743d02b9caae0979b79f5086a6a6964
This commit is contained in:
parent
359a707663
commit
f6481b3c01
1 changed files with 20 additions and 45 deletions
|
|
@ -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)));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue