diff options
author | AnotherTest <ali.mpfard@gmail.com> | 2020-07-12 01:41:24 +0430 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-07-16 16:01:10 +0200 |
commit | 95fc7dd03ac49ddf1d155f27c64c6efd2934f250 (patch) | |
tree | d42466a8a7736c79408ca35ef7e3b3eb2e31c7b1 | |
parent | 9c1da8fca113a8ac4df9cb82b0d5c03c6eb119be (diff) | |
download | serenity-95fc7dd03ac49ddf1d155f27c64c6efd2934f250.zip |
Shell: Parse lists serially, and flatten them only when needed
This allows `((1 2 3) (4 5 6))` to remain nested until we explicitly
flatten it out.
-rw-r--r-- | Shell/AST.cpp | 99 | ||||
-rw-r--r-- | Shell/AST.h | 10 | ||||
-rw-r--r-- | Shell/Parser.cpp | 20 | ||||
-rw-r--r-- | Shell/Shell.cpp | 12 |
4 files changed, 94 insertions, 47 deletions
diff --git a/Shell/AST.cpp b/Shell/AST.cpp index 1e2261ba2e..fe167773c4 100644 --- a/Shell/AST.cpp +++ b/Shell/AST.cpp @@ -216,33 +216,59 @@ And::~And() void ListConcatenate::dump(int level) const { Node::dump(level); - m_element->dump(level + 1); - m_list->dump(level + 1); + for (auto& element : m_list) + element->dump(level + 1); } RefPtr<Value> ListConcatenate::run(RefPtr<Shell> shell) { - auto list = m_list->run(shell)->resolve_without_cast(shell); - auto element = m_element->run(shell)->resolve_without_cast(shell); + RefPtr<Value> result = nullptr; - if (list->is_command() || element->is_command()) { - auto joined_commands = join_commands(element->resolve_as_commands(shell), list->resolve_as_commands(shell)); + for (auto& element : m_list) { + if (!result) { + result = create<ListValue>({ element->run(shell)->resolve_without_cast(shell) }); + continue; + } + auto element_value = element->run(shell)->resolve_without_cast(shell); + + if (result->is_command() || element_value->is_command()) { + auto joined_commands = join_commands(result->resolve_as_commands(shell), element_value->resolve_as_commands(shell)); + + if (joined_commands.size() == 1) + result = create<CommandValue>(joined_commands[0]); + else + result = create<CommandSequenceValue>(move(joined_commands)); + } else { + Vector<RefPtr<Value>> values; - if (joined_commands.size() == 1) - return create<CommandValue>(joined_commands[0]); - return create<CommandSequenceValue>(move(joined_commands)); + if (result->is_list_without_resolution()) { + values.append(static_cast<ListValue*>(result.ptr())->values()); + } else { + for (auto& result : result->resolve_as_list(shell)) + values.append(create<StringValue>(result)); + } + + values.append(move(element_value)); + + result = create<ListValue>(move(values)); + } } + if (!result) + return create<ListValue>({}); - return create<ListValue>({ move(element), move(list) }); + return result; } void ListConcatenate::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata) { auto first = metadata.is_first_in_list; metadata.is_first_in_list = false; - m_list->highlight_in_editor(editor, shell, metadata); + metadata.is_first_in_list = first; - m_element->highlight_in_editor(editor, shell, metadata); + for (auto& element : m_list) { + element->highlight_in_editor(editor, shell, metadata); + metadata.is_first_in_list = false; + } } HitTestResult ListConcatenate::hit_test_position(size_t offset) @@ -250,29 +276,37 @@ HitTestResult ListConcatenate::hit_test_position(size_t offset) if (!position().contains(offset)) return {}; - auto result = m_element->hit_test_position(offset); - if (result.matching_node) - return result; - result = m_list->hit_test_position(offset); - if (!result.closest_node_with_semantic_meaning) - result.closest_node_with_semantic_meaning = this; - return result; + bool first = true; + for (auto& element : m_list) { + auto result = element->hit_test_position(offset); + if (!result.closest_node_with_semantic_meaning && !first) + result.closest_node_with_semantic_meaning = this; + if (result.matching_node) + return result; + first = false; + } + + return {}; } RefPtr<Node> ListConcatenate::leftmost_trivial_literal() const { - return m_element->leftmost_trivial_literal(); + if (m_list.is_empty()) + return nullptr; + + return m_list.first()->leftmost_trivial_literal(); } -ListConcatenate::ListConcatenate(Position position, RefPtr<Node> element, RefPtr<Node> list) +ListConcatenate::ListConcatenate(Position position, Vector<RefPtr<Node>> list) : Node(move(position)) - , m_element(move(element)) , m_list(move(list)) { - if (m_element->is_syntax_error()) - set_is_syntax_error(m_element->syntax_error_node()); - else if (m_list->is_syntax_error()) - set_is_syntax_error(m_list->syntax_error_node()); + for (auto& element : m_list) { + if (element->is_syntax_error()) { + set_is_syntax_error(element->syntax_error_node()); + break; + } + } } ListConcatenate::~ListConcatenate() @@ -451,9 +485,9 @@ RefPtr<Value> CastToList::run(RefPtr<Shell> shell) if (!m_inner) return create<ListValue>({}); - auto inner_value = m_inner->run(shell); + auto inner_value = m_inner->run(shell)->resolve_without_cast(shell); - if (inner_value->is_command()) + if (inner_value->is_command() || inner_value->is_list()) return inner_value; auto values = inner_value->resolve_as_list(shell); @@ -1783,6 +1817,15 @@ Vector<String> ListValue::resolve_as_list(RefPtr<Shell> shell) return values; } +RefPtr<Value> ListValue::resolve_without_cast(RefPtr<Shell> shell) +{ + Vector<RefPtr<Value>> values; + for (auto& value : m_contained_values) + values.append(value->resolve_without_cast(shell)); + + return create<ListValue>(move(values)); +} + CommandValue::~CommandValue() { } diff --git a/Shell/AST.h b/Shell/AST.h index 2e9c74ea5c..58945126f4 100644 --- a/Shell/AST.h +++ b/Shell/AST.h @@ -164,6 +164,7 @@ public: virtual bool is_job() const { return false; } virtual bool is_list() const { return false; } virtual bool is_string() const { return false; } + virtual bool is_list_without_resolution() const { return false; } }; class CommandValue final : public Value { @@ -221,14 +222,18 @@ private: class ListValue final : public Value { public: virtual Vector<String> resolve_as_list(RefPtr<Shell>) override; + virtual RefPtr<Value> resolve_without_cast(RefPtr<Shell>) override; virtual ~ListValue(); virtual bool is_list() const override { return true; } + virtual bool is_list_without_resolution() const override { return true; } ListValue(Vector<String> values); ListValue(Vector<RefPtr<Value>> values) : m_contained_values(move(values)) { } + const Vector<RefPtr<Value>>& values() const { return m_contained_values; } + private: Vector<RefPtr<Value>> m_contained_values; }; @@ -389,7 +394,7 @@ private: class ListConcatenate final : public Node { public: - ListConcatenate(Position, RefPtr<Node>, RefPtr<Node>); + ListConcatenate(Position, Vector<RefPtr<Node>>); virtual ~ListConcatenate(); private: @@ -401,8 +406,7 @@ private: virtual bool is_list() const override { return true; } virtual RefPtr<Node> leftmost_trivial_literal() const override; - RefPtr<Node> m_element; - RefPtr<Node> m_list; + Vector<RefPtr<Node>> m_list; }; class Background final : public Node { diff --git a/Shell/Parser.cpp b/Shell/Parser.cpp index c19f2d3664..4a56761f65 100644 --- a/Shell/Parser.cpp +++ b/Shell/Parser.cpp @@ -420,19 +420,19 @@ RefPtr<AST::Node> Parser::parse_list_expression() consume_while(is_whitespace); auto rule_start = push_start(); + Vector<RefPtr<AST::Node>> nodes; - auto expr = parse_expression(); - if (!expr) - return nullptr; + do { + auto expr = parse_expression(); + if (!expr) + break; + nodes.append(move(expr)); + } while (!consume_while(is_whitespace).is_empty()); - if (consume_while(is_whitespace).is_empty()) - return expr; - - auto list = parse_list_expression(); - if (!list) - return create<AST::CastToList>(move(expr)); + if (nodes.is_empty()) + return nullptr; - return create<AST::ListConcatenate>(move(expr), move(list)); // Join Element List + return create<AST::ListConcatenate>(move(nodes)); // Concatenate List } RefPtr<AST::Node> Parser::parse_expression() diff --git a/Shell/Shell.cpp b/Shell/Shell.cpp index 4909b3e8b9..a7cfbcaaae 100644 --- a/Shell/Shell.cpp +++ b/Shell/Shell.cpp @@ -361,19 +361,19 @@ int Shell::run_command(const StringView& cmd) if (!command) return 0; +#ifdef SH_DEBUG + dbg() << "Command follows"; + command->dump(0); +#endif + if (command->is_syntax_error()) { auto& error_node = command->syntax_error_node(); auto& position = error_node.position(); fprintf(stderr, "Shell: Syntax error in command: %s\n", error_node.error_text().characters()); - fprintf(stderr, "Around '%.*s'\n", (int)min(position.end_offset - position.start_offset, (size_t)10), cmd.characters_without_null_termination() + position.start_offset); + fprintf(stderr, "Around '%.*s' at %zu:%zu\n", (int)min(position.end_offset - position.start_offset, (size_t)10), cmd.characters_without_null_termination() + position.start_offset, position.start_offset, position.end_offset); return 1; } -#ifdef SH_DEBUG - dbg() << "Command follows"; - command->dump(0); -#endif - tcgetattr(0, &termios); auto result = command->run(*this); |