mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 01:22:43 +00:00 
			
		
		
		
	Shell: Add the (now) free subshell support
This commit is contained in:
		
							parent
							
								
									0fd8d5ad3d
								
							
						
					
					
						commit
						b194d79c53
					
				
					 4 changed files with 92 additions and 0 deletions
				
			
		|  | @ -1569,6 +1569,51 @@ Sequence::~Sequence() | |||
| { | ||||
| } | ||||
| 
 | ||||
| void Subshell::dump(int level) const | ||||
| { | ||||
|     Node::dump(level); | ||||
|     if (m_block) | ||||
|         m_block->dump(level + 1); | ||||
| } | ||||
| 
 | ||||
| RefPtr<Value> Subshell::run(RefPtr<Shell> shell) | ||||
| { | ||||
|     if (!m_block) | ||||
|         return create<ListValue>({}); | ||||
| 
 | ||||
|     return m_block->run(shell); | ||||
| } | ||||
| 
 | ||||
| void Subshell::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata) | ||||
| { | ||||
|     metadata.is_first_in_list = true; | ||||
|     if (m_block) | ||||
|         m_block->highlight_in_editor(editor, shell, metadata); | ||||
| } | ||||
| 
 | ||||
| HitTestResult Subshell::hit_test_position(size_t offset) | ||||
| { | ||||
|     if (!position().contains(offset)) | ||||
|         return {}; | ||||
| 
 | ||||
|     if (m_block) | ||||
|         return m_block->hit_test_position(offset); | ||||
| 
 | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| Subshell::Subshell(Position position, RefPtr<Node> block) | ||||
|     : Node(move(position)) | ||||
|     , m_block(block) | ||||
| { | ||||
|     if (m_block && m_block->is_syntax_error()) | ||||
|         set_is_syntax_error(m_block->syntax_error_node()); | ||||
| } | ||||
| 
 | ||||
| Subshell::~Subshell() | ||||
| { | ||||
| } | ||||
| 
 | ||||
| void SimpleVariable::dump(int level) const | ||||
| { | ||||
|     Node::dump(level); | ||||
|  |  | |||
							
								
								
									
										16
									
								
								Shell/AST.h
									
										
									
									
									
								
							
							
						
						
									
										16
									
								
								Shell/AST.h
									
										
									
									
									
								
							|  | @ -806,6 +806,22 @@ private: | |||
|     RefPtr<Node> m_right; | ||||
| }; | ||||
| 
 | ||||
| class Subshell final : public Node { | ||||
| public: | ||||
|     Subshell(Position, RefPtr<Node> block); | ||||
|     virtual ~Subshell(); | ||||
| 
 | ||||
| private: | ||||
|     virtual void dump(int level) const override; | ||||
|     virtual RefPtr<Value> run(RefPtr<Shell>) override; | ||||
|     virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override; | ||||
|     virtual HitTestResult hit_test_position(size_t) override; | ||||
|     virtual String class_name() const override { return "Subshell"; } | ||||
|     virtual bool would_execute() const override { return true; } | ||||
| 
 | ||||
|     RefPtr<AST::Node> m_block; | ||||
| }; | ||||
| 
 | ||||
| class SimpleVariable final : public Node { | ||||
| public: | ||||
|     SimpleVariable(Position, String); | ||||
|  |  | |||
|  | @ -366,6 +366,9 @@ RefPtr<AST::Node> Parser::parse_control_structure() | |||
|     if (auto if_expr = parse_if_expr()) | ||||
|         return if_expr; | ||||
| 
 | ||||
|     if (auto subshell = parse_subshell()) | ||||
|         return subshell; | ||||
| 
 | ||||
|     return nullptr; | ||||
| } | ||||
| 
 | ||||
|  | @ -510,6 +513,29 @@ RefPtr<AST::Node> Parser::parse_if_expr() | |||
|     return create<AST::IfCond>(else_position, move(condition), move(true_branch), nullptr); // If expr true_branch
 | ||||
| } | ||||
| 
 | ||||
| RefPtr<AST::Node> Parser::parse_subshell() | ||||
| { | ||||
|     auto rule_start = push_start(); | ||||
|     if (!expect('{')) | ||||
|         return nullptr; | ||||
| 
 | ||||
|     auto body = parse_toplevel(); | ||||
| 
 | ||||
|     { | ||||
|         auto cbrace_error_start = push_start(); | ||||
|         if (!expect('}')) { | ||||
|             auto error_start = push_start(); | ||||
|             RefPtr<AST::SyntaxError> syntax_error = create<AST::SyntaxError>("Expected a close brace '}' to end a subshell"); | ||||
|             if (body) | ||||
|                 body->set_is_syntax_error(*syntax_error); | ||||
|             else | ||||
|                 body = syntax_error; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return create<AST::Subshell>(move(body)); | ||||
| } | ||||
| 
 | ||||
| RefPtr<AST::Node> Parser::parse_redirection() | ||||
| { | ||||
|     auto rule_start = push_start(); | ||||
|  |  | |||
|  | @ -53,6 +53,7 @@ private: | |||
|     RefPtr<AST::Node> parse_control_structure(); | ||||
|     RefPtr<AST::Node> parse_for_loop(); | ||||
|     RefPtr<AST::Node> parse_if_expr(); | ||||
|     RefPtr<AST::Node> parse_subshell(); | ||||
|     RefPtr<AST::Node> parse_redirection(); | ||||
|     RefPtr<AST::Node> parse_list_expression(); | ||||
|     RefPtr<AST::Node> parse_expression(); | ||||
|  | @ -129,6 +130,8 @@ pipe_sequence :: command '|' pipe_sequence | |||
| 
 | ||||
| control_structure :: for_expr | ||||
|                    | if_expr | ||||
|                    | subshell | ||||
| 
 | ||||
| for_expr :: 'for' ws+ (identifier ' '+ 'in' ws*)? expression ws+ '{' toplevel '}' | ||||
| 
 | ||||
| if_expr :: 'if' ws+ or_logical_sequence ws+ '{' toplevel '}' else_clause? | ||||
|  | @ -136,6 +139,8 @@ if_expr :: 'if' ws+ or_logical_sequence ws+ '{' toplevel '}' else_clause? | |||
| else_clause :: else '{' toplevel '}' | ||||
|              | else if_expr | ||||
| 
 | ||||
| subshell :: '{' toplevel '}' | ||||
| 
 | ||||
| command :: redirection command | ||||
|          | list_expression command? | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 AnotherTest
						AnotherTest