From 165ead4adbf8494db82f7be35c6f8d52ac47ebef Mon Sep 17 00:00:00 2001 From: _ov4 Date: Tue, 15 Sep 2026 13:48:09 +0000 Subject: add subshell ast prepare for real subshell and expansion --- include/lexer/ast.h | 2 ++ module-test/lexer_test.cc | 23 ++++++++++++++++++++--- src/lexer/ast.cc | 20 ++++++++++++++++++++ 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/include/lexer/ast.h b/include/lexer/ast.h index 3434aa3..d4b0fd5 100644 --- a/include/lexer/ast.h +++ b/include/lexer/ast.h @@ -20,6 +20,8 @@ public: string command_text; size_t left = string::npos; size_t right = string::npos; + + bool subshell; }; } diff --git a/module-test/lexer_test.cc b/module-test/lexer_test.cc index 623b9ec..364c890 100644 --- a/module-test/lexer_test.cc +++ b/module-test/lexer_test.cc @@ -6,7 +6,9 @@ g++ \ src/lexer/token.cc \ src/lexer/ast.cc \ src/lexer/symbol_property.cc \ - -std=c++23 -Iinclude -Ithird_party/magic_enum/include + -std=c++23 -Iinclude -Ithird_party/magic_enum/include \ + -O0 -ggdb3 -fno-omit-frame-pointer -fno-inline -D_GLIBCXX_ASSERTIONS \ + -o module-test/lexer_test.out */ #include @@ -35,7 +37,7 @@ constexpr int MAXLINE = 1024; int main() { verbose = true; - int test_case = 13; + int test_case = 15; string s; switch (test_case) @@ -104,6 +106,16 @@ int main() s = "alpha&beta"; break; + // simple subshell test + case 14: + s = "alpha && (beta)"; + break; + + // complex subshell test + case 15: + s = "alpha && (beta || gamma) && (sleep &)"; + break; + default: return 0; } @@ -138,7 +150,12 @@ int main() cout << "---------- AST ----------" << endl; for (size_t i = 0; i < lexer_instance.ast.size(); i++) { - print("{}: type: {} left: {} right: {}", i, magic_enum::enum_name(lexer_instance.ast[i].token_type), lexer_instance.ast[i].left, lexer_instance.ast[i].right); + print("{}: type: {} left: {} right: {}, subshell {}", + i, + magic_enum::enum_name(lexer_instance.ast[i].token_type), + lexer_instance.ast[i].left, + lexer_instance.ast[i].right, + lexer_instance.ast[i].subshell ? "TRUE" : "FALSE"); if (lexer_instance.ast[i].token_type == TEXT) print(" command: {}", lexer_instance.ast[i].command_text); println(); diff --git a/src/lexer/ast.cc b/src/lexer/ast.cc index 55b4c42..292728b 100644 --- a/src/lexer/ast.cc +++ b/src/lexer/ast.cc @@ -10,6 +10,7 @@ #include "lexer/symbol_property.h" #include "util/io.h" #include "error.h" +#include "magic_enum/magic_enum.hpp" using namespace std; @@ -62,6 +63,25 @@ void T_lexer::parse(size_t cmd_begin, size_t cmd_end, size_t ast_vec) int max_depth = -1; size_t found_pos = string::npos; + // if it's fully inside bracket + // then it's subshell + loggerln("parse: left token type: {}, right: {}", + magic_enum::enum_name(token[cmd_begin].token_type), + magic_enum::enum_name(token[cmd_end-1].token_type)); + if (token[cmd_begin].token_type == LEFT_BRACKET && token[cmd_end-1].token_type == RIGHT_BRACKET) + { + ast[ast_vec].subshell = true; + loggerln("parse: detect subshell {}", ast_vec); + + // eat () subshell token + cmd_begin++; + cmd_end--; + } + else + { + ast[ast_vec].subshell = false; + } + for (size_t i = cmd_begin; i < cmd_end; i++) { if (token[i].bracket_depth > max_depth) -- cgit v1.3.1-4-g156e