浏览代码

Shell: Allow a command sequence to be delimited by newlines

AnotherTest 5 年之前
父节点
当前提交
034be8e74c
共有 3 个文件被更改,包括 26 次插入10 次删除
  1. 18 3
      Shell/Parser.cpp
  2. 6 1
      Shell/Parser.h
  3. 2 6
      Shell/Shell.cpp

+ 18 - 3
Shell/Parser.cpp

@@ -102,6 +102,11 @@ static constexpr auto is_not(char c)
     return [c](char ch) { return ch != c; };
 }
 
+static constexpr auto is_any_of(StringView s)
+{
+    return [s](char ch) { return s.contains(ch); };
+}
+
 static inline char to_byte(char a, char b)
 {
     char buf[3] { a, b, 0 };
@@ -139,6 +144,15 @@ RefPtr<AST::Node> Parser::parse_sequence()
     auto rule_start = push_start();
     auto var_decls = parse_variable_decls();
 
+    switch (peek()) {
+    case ';':
+    case '\n':
+        consume_while(is_any_of("\n;"));
+        break;
+    default:
+        break;
+    }
+
     auto pipe_seq = parse_pipe_sequence();
     if (!pipe_seq)
         return var_decls;
@@ -150,7 +164,8 @@ RefPtr<AST::Node> Parser::parse_sequence()
 
     switch (peek()) {
     case ';':
-        consume();
+    case '\n':
+        consume_while(is_any_of("\n;"));
         if (auto expr = parse_sequence()) {
             return create<AST::Sequence>(move(pipe_seq), move(expr)); // Sequence
         }
@@ -429,7 +444,7 @@ RefPtr<AST::Node> Parser::parse_expression()
         return expr;
     };
 
-    if (strchr("&|[]){} ;<>", starting_char) != nullptr)
+    if (strchr("&|[]){} ;<>\n", starting_char) != nullptr)
         return nullptr;
 
     if (isdigit(starting_char)) {
@@ -710,7 +725,7 @@ RefPtr<AST::Node> Parser::parse_bareword()
     auto rule_start = push_start();
     StringBuilder builder;
     auto is_acceptable_bareword_character = [](char c) {
-        return strchr("\\\"'*$&#|()[]{} ?;<>", c) == nullptr;
+        return strchr("\\\"'*$&#|()[]{} ?;<>\n", c) == nullptr;
     };
     while (!at_end()) {
         char ch = peek();

+ 6 - 1
Shell/Parser.h

@@ -100,11 +100,15 @@ private:
 constexpr auto the_grammar = R"(
 toplevel :: sequence?
 
-sequence :: variable_decls? pipe_sequence ';' sequence
+sequence :: variable_decls? pipe_sequence terminator sequence
           | variable_decls? pipe_sequence '&'
           | variable_decls? pipe_sequence '&' '&' sequence
           | variable_decls? pipe_sequence '|' '|' sequence
           | variable_decls? pipe_sequence
+          | variable_decls? terminator pipe_sequence
+
+terminator :: ';'
+            | '\n'
 
 variable_decls :: identifier '=' expression (' '+ variable_decls)? ' '*
                 | identifier '=' '(' pipe_sequence ')' (' '+ variable_decls)? ' '*
@@ -118,6 +122,7 @@ command :: redirection command
 redirection :: number? '>'{1,2} ' '* string_composite
              | number? '<' ' '* string_composite
              | number? '>' '&' number
+             | number? '>' '&' '-'
 
 list_expression :: ' '* expression (' '+ list_expression)?
 

+ 2 - 6
Shell/Shell.cpp

@@ -497,12 +497,8 @@ bool Shell::run_file(const String& filename)
         return false;
     }
     auto file = file_result.value();
-    for (;;) {
-        auto line = file->read_line(4096);
-        if (line.is_null())
-            break;
-        run_command(String::copy(line, Chomp));
-    }
+    auto data = file->read_all();
+    run_command(data);
     return true;
 }
 void Shell::take_back_stdin()