Преглед изворни кода

Shell: Implement `for_each_entry()` for syntactic list nodes

This allows correct iteration over nested lists.
Also store values to variables without resolving them, to delay the
resolution step as much as possible (this helps with storing nested
lists in variables).
AnotherTest пре 4 година
родитељ
комит
1c78d12f1c
2 измењених фајлова са 24 додато и 10 уклоњено
  1. 22 10
      Userland/Shell/AST.cpp
  2. 2 0
      Userland/Shell/AST.h

+ 22 - 10
Userland/Shell/AST.cpp

@@ -390,6 +390,17 @@ RefPtr<Value> ListConcatenate::run(RefPtr<Shell> shell)
     return result;
     return result;
 }
 }
 
 
+void ListConcatenate::for_each_entry(RefPtr<Shell> shell, Function<IterationDecision(NonnullRefPtr<Value>)> callback)
+{
+    for (auto& entry : m_list) {
+        auto value = entry->run(shell);
+        if (!value)
+            continue;
+        if (callback(value.release_nonnull()) == IterationDecision::Break)
+            break;
+    }
+}
+
 void ListConcatenate::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata)
 void ListConcatenate::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata)
 {
 {
     auto first = metadata.is_first_in_list;
     auto first = metadata.is_first_in_list;
@@ -694,6 +705,12 @@ RefPtr<Value> CastToList::run(RefPtr<Shell> shell)
     return create<ListValue>(cast_values);
     return create<ListValue>(cast_values);
 }
 }
 
 
+void CastToList::for_each_entry(RefPtr<Shell> shell, Function<IterationDecision(NonnullRefPtr<Value>)> callback)
+{
+    if (m_inner)
+        m_inner->for_each_entry(shell, move(callback));
+}
+
 void CastToList::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata)
 void CastToList::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata)
 {
 {
     if (m_inner)
     if (m_inner)
@@ -1046,7 +1063,7 @@ FunctionDeclaration::~FunctionDeclaration()
 void ForLoop::dump(int level) const
 void ForLoop::dump(int level) const
 {
 {
     Node::dump(level);
     Node::dump(level);
-    print_indented(String::format("%s in\n", m_variable_name.characters()), level + 1);
+    print_indented(String::format("%s in", m_variable_name.characters()), level + 1);
     if (m_iterated_expression)
     if (m_iterated_expression)
         m_iterated_expression->dump(level + 2);
         m_iterated_expression->dump(level + 2);
     else
     else
@@ -1075,6 +1092,9 @@ RefPtr<Value> ForLoop::run(RefPtr<Shell> shell)
             return IterationDecision::Continue;
             return IterationDecision::Continue;
         }
         }
 
 
+        if (!shell->has_error(Shell::ShellError::None))
+            return IterationDecision::Break;
+
         if (block_value->is_job()) {
         if (block_value->is_job()) {
             auto job = static_cast<JobValue*>(block_value.ptr())->job();
             auto job = static_cast<JobValue*>(block_value.ptr())->job();
             if (!job || job->is_running_in_background())
             if (!job || job->is_running_in_background())
@@ -2855,15 +2875,7 @@ RefPtr<Value> VariableDeclarations::run(RefPtr<Shell> shell)
         ASSERT(name_value.size() == 1);
         ASSERT(name_value.size() == 1);
         auto name = name_value[0];
         auto name = name_value[0];
         auto value = var.value->run(shell);
         auto value = var.value->run(shell);
-        if (value->is_list()) {
-            auto parts = value->resolve_as_list(shell);
-            shell->set_local_variable(name, adopt(*new ListValue(move(parts))));
-        } else if (value->is_command()) {
-            shell->set_local_variable(name, value);
-        } else {
-            auto part = value->resolve_as_list(shell);
-            shell->set_local_variable(name, adopt(*new StringValue(part[0])));
-        }
+        shell->set_local_variable(name, value.release_nonnull());
     }
     }
 
 
     return create<ListValue>({});
     return create<ListValue>({});

+ 2 - 0
Userland/Shell/AST.h

@@ -558,6 +558,7 @@ public:
 private:
 private:
     NODE(ListConcatenate);
     NODE(ListConcatenate);
     virtual void dump(int level) const override;
     virtual void dump(int level) const override;
+    virtual void for_each_entry(RefPtr<Shell> shell, Function<IterationDecision(NonnullRefPtr<Value>)> callback) override;
     virtual RefPtr<Value> run(RefPtr<Shell>) override;
     virtual RefPtr<Value> run(RefPtr<Shell>) override;
     virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
     virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
     virtual HitTestResult hit_test_position(size_t) override;
     virtual HitTestResult hit_test_position(size_t) override;
@@ -656,6 +657,7 @@ private:
     NODE(CastToList);
     NODE(CastToList);
     virtual void dump(int level) const override;
     virtual void dump(int level) const override;
     virtual RefPtr<Value> run(RefPtr<Shell>) override;
     virtual RefPtr<Value> run(RefPtr<Shell>) override;
+    virtual void for_each_entry(RefPtr<Shell> shell, Function<IterationDecision(NonnullRefPtr<Value>)> callback) override;
     virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
     virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
     virtual HitTestResult hit_test_position(size_t) override;
     virtual HitTestResult hit_test_position(size_t) override;
     virtual bool is_list() const override { return true; }
     virtual bool is_list() const override { return true; }