浏览代码

Shell: Expand for loop's iterated expr before iterating over it

This only applies to the POSIX mode.
Fixes #21715.
Ali Mohammad Pur 1 年之前
父节点
当前提交
2eb0a8f3d2
共有 2 个文件被更改,包括 38 次插入51 次删除
  1. 11 2
      Userland/Shell/ImmediateFunctions.cpp
  2. 27 49
      Userland/Shell/PosixParser.cpp

+ 11 - 2
Userland/Shell/ImmediateFunctions.cpp

@@ -598,8 +598,17 @@ ErrorOr<RefPtr<AST::Node>> Shell::immediate_reexpand(AST::ImmediateExpression& i
         return nullptr;
     }
 
-    auto value = TRY(TRY(const_cast<AST::Node&>(*arguments.first()).run(*this))->resolve_as_string(*this));
-    return parse(value, m_is_interactive, false);
+    auto values = TRY(TRY(const_cast<AST::Node&>(*arguments.first()).run(*this))->resolve_as_list(*this));
+    auto result = Vector<NonnullRefPtr<AST::Node>> {};
+    for (auto& value : values) {
+        if (auto node = parse(value, m_is_interactive, false))
+            result.append(node.release_nonnull());
+    }
+
+    if (values.size() == 1)
+        return result.take_first();
+
+    return AST::make_ref_counted<AST::ListConcatenate>(invoking_node.position(), move(result));
 }
 
 ErrorOr<RefPtr<AST::Node>> Shell::immediate_length_of_variable(AST::ImmediateExpression& invoking_node, Vector<NonnullRefPtr<AST::Node>> const& arguments)

+ 27 - 49
Userland/Shell/PosixParser.cpp

@@ -123,6 +123,20 @@ static inline bool is_valid_name(StringView word)
 }
 
 namespace Shell::Posix {
+
+template<typename... Args>
+static NonnullRefPtr<AST::Node> reexpand(AST::Position position, Args&&... args)
+{
+    return make_ref_counted<AST::ImmediateExpression>(
+        position,
+        AST::NameWithPosition {
+            "reexpand"_string,
+            position,
+        },
+        Vector<NonnullRefPtr<AST::Node>> { forward<Args>(args)... },
+        Optional<AST::Position> {});
+}
+
 ErrorOr<void> Parser::fill_token_buffer(Optional<Reduction> starting_reduction)
 {
     for (;;) {
@@ -1444,8 +1458,10 @@ ErrorOr<RefPtr<AST::Node>> Parser::parse_for_clause()
         iterated_expression = TRY(Parser { "\"$@\""_string }.parse_word());
     }
 
-    if (saw_in && !saw_newline)
-        iterated_expression = parse_word_list();
+    if (saw_in && !saw_newline) {
+        if (auto list = parse_word_list())
+            iterated_expression = reexpand(peek().position.value_or(empty_position()), list.release_nonnull());
+    }
 
     if (saw_in) {
         if (peek().type == Token::Type::Semicolon || peek().type == Token::Type::Newline)
@@ -1583,19 +1599,13 @@ ErrorOr<RefPtr<AST::Node>> Parser::parse_word()
                 token.position.value_or(empty_position()),
             },
             Vector<NonnullRefPtr<AST::Node>> {
-                make_ref_counted<AST::ImmediateExpression>(
+                reexpand(
                     token.position.value_or(empty_position()),
-                    AST::NameWithPosition {
-                        "reexpand"_string,
+                    make_ref_counted<AST::StringLiteral>(
                         token.position.value_or(empty_position()),
-                    },
-                    Vector<NonnullRefPtr<AST::Node>> {
-                        make_ref_counted<AST::StringLiteral>(
-                            token.position.value_or(empty_position()),
-                            TRY(String::from_utf8(x.source_expression)),
-                            AST::StringLiteral::EnclosureType::DoubleQuotes),
-                    },
-                    Optional<AST::Position> {}) },
+                        TRY(String::from_utf8(x.source_expression)),
+                        AST::StringLiteral::EnclosureType::DoubleQuotes)),
+            },
             Optional<AST::Position> {});
 
         if (word) {
@@ -1714,16 +1724,8 @@ ErrorOr<RefPtr<AST::Node>> Parser::parse_word()
                 Optional<AST::Position> {});
         }
 
-        if (x.expand == ResolvedParameterExpansion::Expand::Word) {
-            node = make_ref_counted<AST::ImmediateExpression>(
-                token.position.value_or(empty_position()),
-                AST::NameWithPosition {
-                    "reexpand"_string,
-                    token.position.value_or(empty_position()),
-                },
-                Vector { node.release_nonnull() },
-                Optional<AST::Position> {});
-        }
+        if (x.expand == ResolvedParameterExpansion::Expand::Word)
+            node = reexpand(token.position.value_or(empty_position()), node.release_nonnull());
 
         if (word) {
             word = make_ref_counted<AST::Juxtaposition>(
@@ -1990,19 +1992,7 @@ ErrorOr<RefPtr<AST::Node>> Parser::parse_simple_command()
         }
 
         auto position = peek().position.value_or(empty_position());
-        nodes.append(make_ref_counted<AST::ImmediateExpression>(
-            position,
-            AST::NameWithPosition {
-                "reexpand"_string,
-                position,
-            },
-            Vector<NonnullRefPtr<AST::Node>> {
-                make_ref_counted<AST::StringLiteral>(
-                    position,
-                    TRY(String::formatted("-e{}", consume().value)),
-                    AST::StringLiteral::EnclosureType::DoubleQuotes),
-            },
-            Optional<AST::Position> {}));
+        nodes.append(reexpand(position, make_ref_counted<AST::StringLiteral>(position, TRY(String::formatted("-e{}", consume().value)), AST::StringLiteral::EnclosureType::DoubleQuotes)));
     }
 
     if (!definitions.is_empty()) {
@@ -2026,19 +2016,7 @@ ErrorOr<RefPtr<AST::Node>> Parser::parse_simple_command()
                     TRY(definition.substring_from_byte_offset_with_shared_superstring(0, split_offset)));
 
                 auto position = peek().position.value_or(empty_position());
-                auto expanded_value = make_ref_counted<AST::ImmediateExpression>(
-                    position,
-                    AST::NameWithPosition {
-                        "reexpand"_string,
-                        position,
-                    },
-                    Vector<NonnullRefPtr<AST::Node>> {
-                        make_ref_counted<AST::StringLiteral>(
-                            position,
-                            TRY(definition.substring_from_byte_offset_with_shared_superstring(split_offset + 1)),
-                            AST::StringLiteral::EnclosureType::DoubleQuotes),
-                    },
-                    Optional<AST::Position> {});
+                auto expanded_value = reexpand(position, make_ref_counted<AST::StringLiteral>(position, TRY(definition.substring_from_byte_offset_with_shared_superstring(split_offset + 1)), AST::StringLiteral::EnclosureType::DoubleQuotes));
 
                 variables.append({ move(name), move(expanded_value) });
             }