From 1ea3471f0d8b44fc9c9310a9492b30aaa15f4f75 Mon Sep 17 00:00:00 2001 From: Max Wash Date: Tue, 12 May 2026 22:58:59 +0100 Subject: [PATCH] parse: implement parsing of complex command arguments --- bshell/parse/syntax/command.c | 134 +++++++++++++++++++++++++++++----- 1 file changed, 115 insertions(+), 19 deletions(-) diff --git a/bshell/parse/syntax/command.c b/bshell/parse/syntax/command.c index 4174b97..501a68b 100644 --- a/bshell/parse/syntax/command.c +++ b/bshell/parse/syntax/command.c @@ -1,7 +1,63 @@ +#include "../../debug.h" #include "../syntax.h" #include +static bool parse_fword(struct parse_ctx *ctx, struct ast_node **out) +{ + if (peek_token_type(ctx) != TOK_WORD_START) { + return false; + } + + discard_token(ctx); + + struct fstring_ast_node *fstring + = (struct fstring_ast_node *)ast_node_create(AST_FSTRING); + if (!fstring) { + ctx->p_status = BSHELL_ERR_NO_MEMORY; + return false; + } + + bool ok = true; + while (ok) { + if (peek_token_type(ctx) == TOK_WORD_END) { + discard_token(ctx); + break; + } + + struct ast_node *item = NULL; + if (peek_token_type(ctx) == TOK_WORD) { + struct word_ast_node *n + = (struct word_ast_node *)ast_node_create( + AST_WORD); + if (!n) { + ctx->p_status = BSHELL_ERR_NO_MEMORY; + ok = false; + break; + } + + n->n_value = claim_token(ctx); + item = (struct ast_node *)n; + } else { + if (!parse_arith_value(ctx, &item)) { + ok = false; + break; + } + } + + fx_queue_push_back(&fstring->n_elements, &item->n_entry); + } + + if (!ok) { + ast_node_destroy((struct ast_node *)fstring); + fstring = NULL; + } + + *out = (struct ast_node *)fstring; + return ok; + return false; +} + static bool parse_cmdcall_arg(struct parse_ctx *ctx, struct ast_node **out) { if (ctx->p_status != BSHELL_SUCCESS) { @@ -16,6 +72,10 @@ static bool parse_cmdcall_arg(struct parse_ctx *ctx, struct ast_node **out) struct ast_node *arg = NULL; switch (tok->tok_type) { + case TOK_WORD_START: + return parse_fword(ctx, out); + case TOK_STR_START: + return parse_fstring(ctx, out); case TOK_WORD: { struct word_ast_node *n = (struct word_ast_node *)ast_node_create(AST_WORD); @@ -29,21 +89,6 @@ static bool parse_cmdcall_arg(struct parse_ctx *ctx, struct ast_node **out) return true; } -#if 0 - case TOK_FLAG: { - struct word_ast_node *n - = (struct word_ast_node *)ast_node_create(AST_WORD); - if (!n) { - ctx->p_status = BSHELL_ERR_NO_MEMORY; - return false; - } - - n->n_value = claim_token(ctx); - *out = (struct ast_node *)n; - return true; - } -#endif - case TOK_VAR: { struct var_ast_node *n = (struct var_ast_node *)ast_node_create(AST_VAR); @@ -84,7 +129,23 @@ static bool parse_cmdcall_arg(struct parse_ctx *ctx, struct ast_node **out) return true; } + case TOK_SYMBOL: + switch (tok->tok_symbol) { + case SYM_LEFT_PAREN: + case SYM_LEFT_BRACE: + case SYM_DOLLAR_LEFT_PAREN: + case SYM_AT_LEFT_BRACE: + case SYM_AT_LEFT_PAREN: + return parse_arith_value(ctx, out); + default: + report_error( + ctx, + "encountered unsupported command arg"); + return false; + } + break; default: + report_error(ctx, "encountered unsupported command arg"); return false; } @@ -218,8 +279,12 @@ bool parse_redirect(struct parse_ctx *ctx, struct ast_node **out) bool append = false; if (fx_wchar_is_number(*str)) { - in_fd = *str - '0'; - str++; + in_fd = 0; + while (fx_wchar_is_number(*str)) { + in_fd *= 10; + in_fd += *str - '0'; + str++; + } } if (*str != '>') { @@ -275,7 +340,7 @@ static bool peek_cmdcall_item(struct parse_ctx *ctx, bool unrestricted) case TOK_VAR: case TOK_VAR_SPLAT: case TOK_STRING: - case TOK_STR_START: + case TOK_WORD_START: return unrestricted; case TOK_SYMBOL: switch (peek_unknown_symbol(ctx)) { @@ -285,6 +350,9 @@ static bool peek_cmdcall_item(struct parse_ctx *ctx, bool unrestricted) case SYM_PIPE: case SYM_AMPERSAND: case SYM_SEMICOLON: + case SYM_RIGHT_PAREN: + case SYM_RIGHT_BRACE: + case SYM_RIGHT_BRACKET: return false; default: return true; @@ -379,7 +447,7 @@ bool parse_command(struct parse_ctx *ctx, struct ast_node **out) struct pipeline_ast_node *pipeline = NULL; while (1) { - if (parse_symbol(ctx, SYM_SEMICOLON) || parse_linefeed(ctx)) { + if (peek_symbol(ctx, SYM_SEMICOLON) || peek_linefeed(ctx)) { break; } @@ -417,3 +485,31 @@ bool parse_command(struct parse_ctx *ctx, struct ast_node **out) return true; } + +bool parse_pipeline( + struct parse_ctx *ctx, + struct ast_node *first_item, + struct ast_node **out) +{ + struct pipeline_ast_node *pipeline + = (struct pipeline_ast_node *)ast_node_create(AST_PIPELINE); + + fx_queue_push_back(&pipeline->n_stages, &first_item->n_entry); + + while (1) { + if (!parse_symbol(ctx, SYM_PIPE)) { + break; + } + + struct ast_node *cmdcall = NULL; + if (!parse_cmdcall(ctx, &cmdcall)) { + ctx->p_status = BSHELL_ERR_BAD_SYNTAX; + return false; + } + + fx_queue_push_back(&pipeline->n_stages, &cmdcall->n_entry); + } + + *out = (struct ast_node *)pipeline; + return true; +}