From 1c78d12f1c2e54ec3dda8cdc66845b1c9393c20d Mon Sep 17 00:00:00 2001 From: AnotherTest Date: Mon, 18 Jan 2021 04:36:19 +0330 Subject: [PATCH] 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). --- Userland/Shell/AST.cpp | 32 ++++++++++++++++++++++---------- Userland/Shell/AST.h | 2 ++ 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/Userland/Shell/AST.cpp b/Userland/Shell/AST.cpp index 42beca71f6..d461b9fd6d 100644 --- a/Userland/Shell/AST.cpp +++ b/Userland/Shell/AST.cpp @@ -390,6 +390,17 @@ RefPtr ListConcatenate::run(RefPtr shell) return result; } +void ListConcatenate::for_each_entry(RefPtr shell, Function)> 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) { auto first = metadata.is_first_in_list; @@ -694,6 +705,12 @@ RefPtr CastToList::run(RefPtr shell) return create(cast_values); } +void CastToList::for_each_entry(RefPtr shell, Function)> callback) +{ + if (m_inner) + m_inner->for_each_entry(shell, move(callback)); +} + void CastToList::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata) { if (m_inner) @@ -1046,7 +1063,7 @@ FunctionDeclaration::~FunctionDeclaration() void ForLoop::dump(int level) const { 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) m_iterated_expression->dump(level + 2); else @@ -1075,6 +1092,9 @@ RefPtr ForLoop::run(RefPtr shell) return IterationDecision::Continue; } + if (!shell->has_error(Shell::ShellError::None)) + return IterationDecision::Break; + if (block_value->is_job()) { auto job = static_cast(block_value.ptr())->job(); if (!job || job->is_running_in_background()) @@ -2855,15 +2875,7 @@ RefPtr VariableDeclarations::run(RefPtr shell) ASSERT(name_value.size() == 1); auto name = name_value[0]; 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({}); diff --git a/Userland/Shell/AST.h b/Userland/Shell/AST.h index 4001b93cb6..feb0cb6ebe 100644 --- a/Userland/Shell/AST.h +++ b/Userland/Shell/AST.h @@ -558,6 +558,7 @@ public: private: NODE(ListConcatenate); virtual void dump(int level) const override; + virtual void for_each_entry(RefPtr shell, Function)> callback) override; virtual RefPtr run(RefPtr) override; virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override; virtual HitTestResult hit_test_position(size_t) override; @@ -656,6 +657,7 @@ private: NODE(CastToList); virtual void dump(int level) const override; virtual RefPtr run(RefPtr) override; + virtual void for_each_entry(RefPtr shell, Function)> callback) override; virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override; virtual HitTestResult hit_test_position(size_t) override; virtual bool is_list() const override { return true; }