Files
bshell/bshell.runtime/parse/lex/statement.c
T
wash edfb3e24a3 bshell: re-organise build into three separate components
bshell: the front-end binary
bshell.runtime: contains the parser, compiler, and classes needed to run bshell scripts
bshell.core: contains the builtin commandlets and aliases
2026-05-25 10:33:29 +01:00

255 lines
6.3 KiB
C

#include "lex-internal.h"
static enum bshell_status statement_hyphen(struct bshell_lex_ctx *ctx)
{
fx_wchar c = peek_char(ctx);
if (!fx_wchar_is_alnum(c)) {
push_symbol(ctx, BSHELL_SYM_HYPHEN);
handle_lex_state_transition(ctx, BSHELL_SYM_HYPHEN);
return BSHELL_SUCCESS;
}
struct bshell_lex_token *tok = NULL;
enum bshell_status status = read_word(
ctx,
READ_NO_SET_TOKEN_START | READ_APPEND_HYPHEN,
&tok);
if (status != BSHELL_SUCCESS) {
return status;
}
unsigned int token_type = BSHELL_TOK_WORD;
if (convert_word_to_number(tok)) {
token_type = tok->tok_type;
/* because of APPEND_HYPHEN (which is needed to ensure operator
* tokens are detected properly), the resulting number will be
* negative.
* this token will be preceded by a HYPHEN token, so the number
* must be positive */
fx_value neg = FX_INT(-1);
fx_value_multiply(&tok->tok_number, &neg, &tok->tok_number);
push_symbol(ctx, BSHELL_SYM_HYPHEN);
} else if (convert_word_to_operator(ctx, tok)) {
token_type = tok->tok_operator;
}
handle_lex_state_transition(ctx, token_type);
enqueue_token(ctx, tok);
return BSHELL_SUCCESS;
}
static enum bshell_status statement_symbol(struct bshell_lex_ctx *ctx)
{
const struct bshell_lex_token_definition *sym = NULL;
enum bshell_status status = read_symbol(ctx, &sym);
if (status != BSHELL_SUCCESS) {
return status;
}
handle_lex_state_transition(ctx, sym->id);
struct bshell_lex_token *tok = NULL;
switch (sym->id) {
case BSHELL_SYM_DQUOTE:
return BSHELL_SUCCESS;
case BSHELL_SYM_HYPHEN:
return statement_hyphen(ctx);
case BSHELL_SYM_SQUOTE:
status = read_literal_string(ctx, &tok);
if (status != BSHELL_SUCCESS) {
return status;
}
enqueue_token(ctx, tok);
return BSHELL_SUCCESS;
case BSHELL_SYM_HASH:
return read_line_comment(ctx);
case BSHELL_SYM_DOLLAR:
status = read_var(ctx, BSHELL_TOK_VAR, &tok);
if (status != BSHELL_SUCCESS) {
return status;
}
enqueue_token(ctx, tok);
return status;
case BSHELL_SYM_AT:
status = read_var(ctx, BSHELL_TOK_VAR_SPLAT, &tok);
if (status != BSHELL_SUCCESS) {
return status;
}
enqueue_token(ctx, tok);
return status;
case BSHELL_SYM_DOLLAR_LEFT_BRACE:
status = read_braced_var(ctx, BSHELL_TOK_VAR, &tok);
if (status != BSHELL_SUCCESS) {
return status;
}
enqueue_token(ctx, tok);
return status;
default:
break;
}
push_symbol(ctx, sym->id);
return BSHELL_SUCCESS;
}
static enum bshell_status statement_word(struct bshell_lex_ctx *ctx)
{
struct bshell_lex_token *word = NULL;
enum bshell_status status = read_word(ctx, 0, &word);
if (status != BSHELL_SUCCESS) {
return status;
}
struct bshell_lex_state *state = lex_state_get(ctx);
bool enable_keywords = !(state->s_flags & STATEMENT_F_DISABLE_KEYWORDS);
unsigned int token = BSHELL_TOK_WORD;
if (enable_keywords && convert_word_to_keyword(word)) {
token = word->tok_keyword;
} else if (convert_word_to_number(word)) {
token = word->tok_type;
}
handle_lex_state_transition(ctx, token);
enqueue_token(ctx, word);
return BSHELL_SUCCESS;
}
static enum bshell_status statement_pump_token(struct bshell_lex_ctx *ctx)
{
fx_wchar c = peek_char(ctx);
bool newline = false;
set_token_start(ctx);
while (fx_wchar_is_space(c)) {
if (c == '\n') {
newline = true;
}
set_token_end(ctx);
advance_char_noread(ctx);
c = peek_char_noread(ctx);
}
if (newline) {
struct bshell_lex_token *tok = bshell_lex_token_create(BSHELL_TOK_LINEFEED);
enqueue_token(ctx, tok);
handle_lex_state_transition(ctx, BSHELL_TOK_LINEFEED);
return BSHELL_SUCCESS;
}
if (char_can_begin_symbol(ctx, c)) {
return statement_symbol(ctx);
}
if (char_has_flags(ctx, c, BSHELL_LEX_TOKEN_UNARY_ARITHMETIC)) {
lex_state_change(ctx, BSHELL_LEX_STATE_ARITHMETIC);
return BSHELL_SUCCESS;
}
return statement_word(ctx);
}
static const struct bshell_lex_state_link links[] = {
LINK_PUSH(BSHELL_SYM_DQUOTE, BSHELL_LEX_STATE_STRING, 0),
/* arithmetic tokens */
LINK_CHANGE(BSHELL_TOK_KEYWORD, BSHELL_LEX_STATE_ARITHMETIC),
LINK_CHANGE(BSHELL_SYM_SQUOTE, BSHELL_LEX_STATE_ARITHMETIC),
LINK_CHANGE(BSHELL_TOK_INT, BSHELL_LEX_STATE_ARITHMETIC),
LINK_CHANGE(BSHELL_TOK_DOUBLE, BSHELL_LEX_STATE_ARITHMETIC),
LINK_PUSH(BSHELL_SYM_DOLLAR, BSHELL_LEX_STATE_ARITHMETIC, 0),
LINK_PUSH_WITH_TERM(
BSHELL_SYM_DOLLAR_LEFT_BRACE,
BSHELL_LEX_STATE_ARITHMETIC,
0,
BSHELL_SYM_RIGHT_BRACE),
LINK_CHANGE(BSHELL_SYM_AT_LEFT_BRACE, BSHELL_LEX_STATE_ARITHMETIC),
LINK_CHANGE(BSHELL_SYM_AT_LEFT_PAREN, BSHELL_LEX_STATE_ARITHMETIC),
LINK_PUSH_WITH_TERM(
BSHELL_SYM_AT_LEFT_BRACE,
BSHELL_LEX_STATE_HASHTABLE,
0,
BSHELL_SYM_RIGHT_BRACE),
LINK_PUSH(BSHELL_SYM_AT, BSHELL_LEX_STATE_ARITHMETIC, 0),
LINK_CHANGE(BSHELL_SYM_LEFT_PAREN, BSHELL_LEX_STATE_ARITHMETIC),
LINK_CHANGE(BSHELL_SYM_LEFT_BRACKET, BSHELL_LEX_STATE_ARITHMETIC),
LINK_CHANGE(BSHELL_SYM_BANG, BSHELL_LEX_STATE_ARITHMETIC),
LINK_PUSH_WITH_TERM(
BSHELL_SYM_LEFT_PAREN,
BSHELL_LEX_STATE_STATEMENT,
STATEMENT_F_DISABLE_KEYWORDS,
BSHELL_SYM_RIGHT_PAREN),
/* statement tokens */
LINK_PUSH_WITH_TERM(
BSHELL_SYM_LEFT_BRACE,
BSHELL_LEX_STATE_STATEMENT,
0,
BSHELL_SYM_RIGHT_BRACE),
LINK_PUSH_WITH_TERM(
BSHELL_SYM_DOLLAR_LEFT_PAREN,
BSHELL_LEX_STATE_STATEMENT,
0,
BSHELL_SYM_RIGHT_PAREN),
/* command tokens */
LINK_CHANGE(BSHELL_KW_FUNC, BSHELL_LEX_STATE_COMMAND),
LINK_CHANGE(BSHELL_SYM_AMPERSAND, BSHELL_LEX_STATE_COMMAND),
LINK_CHANGE(BSHELL_TOK_WORD, BSHELL_LEX_STATE_COMMAND),
LINK_END,
};
static const unsigned int keywords[] = {
BSHELL_KW_FUNC,
BSHELL_KW_IF,
BSHELL_KW_ELSEIF,
BSHELL_KW_ELSE,
BSHELL_KW_NONE,
};
static const unsigned int operators[] = {
BSHELL_TKOP_BNOT,
BSHELL_TKOP_NOT,
BSHELL_TKOP_NONE,
};
static const unsigned int symbols[] = {
BSHELL_SYM_AMPERSAND,
BSHELL_SYM_BANG,
BSHELL_SYM_SQUOTE,
BSHELL_SYM_DQUOTE,
BSHELL_SYM_HASH,
BSHELL_SYM_AT,
BSHELL_SYM_AT_LEFT_PAREN,
BSHELL_SYM_AT_LEFT_BRACE,
BSHELL_SYM_PIPE,
BSHELL_SYM_COMMA,
BSHELL_SYM_SEMICOLON,
BSHELL_SYM_LEFT_BRACE,
BSHELL_SYM_RIGHT_BRACE,
BSHELL_SYM_LEFT_BRACKET,
BSHELL_SYM_RIGHT_BRACKET,
BSHELL_SYM_LEFT_PAREN,
BSHELL_SYM_RIGHT_PAREN,
BSHELL_SYM_NONE,
};
const struct bshell_lex_state_type lex_statement_state = {
.s_id = BSHELL_LEX_STATE_STATEMENT,
.s_pump_token = statement_pump_token,
.s_links = links,
.s_keywords = keywords,
.s_operators = operators,
.s_symbols = symbols,
};