Files
bshell/bshell.runtime/operator.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

275 lines
9.9 KiB
C

#include <bshell/parse/token.h>
#include <bshell/runtime/operator.h>
#define OP(id, p, a, l, u) \
[BSHELL_OP_##id] = { \
.op_id = (BSHELL_OP_##id), \
.op_precedence = (BSHELL_PRECEDENCE_##p), \
.op_associativity = (BSHELL_ASSOCIATIVITY_##a), \
.op_location = (BSHELL_OPL_##l), \
.op_arity = (BSHELL_OPA_##u), \
}
#define BSHELL_TOK_OP(id, tok) \
[BSHELL_TOK_##tok - __BSHELL_TOK_INDEX_BASE] = &operators[BSHELL_OP_##id]
#define BSHELL_SYM_OP(id, sym) \
[BSHELL_SYM_##sym - __BSHELL_SYM_INDEX_BASE] = &operators[BSHELL_OP_##id]
#define BSHELL_KW_OP(id, kw) [BSHELL_KW_##kw - __BSHELL_KW_INDEX_BASE] = &operators[BSHELL_OP_##id]
#define BSHELL_TKOP_OP(id, kw) \
[BSHELL_TKOP_##kw - __BSHELL_TKOP_INDEX_BASE] \
= &operators[BSHELL_OP_##id]
/* clang-format off */
static const struct bshell_operator_info operators[] = {
OP(ACCESS, MEMBER_ACCESS, LEFT, INFIX, BINARY),
OP(CONDITIONAL_ACCESS, MEMBER_ACCESS, LEFT, INFIX, BINARY),
OP(STATIC_ACCESS, STATIC_ACCESS, LEFT, INFIX, BINARY),
OP(SUBSCRIPT, SUBSCRIPT, LEFT, INFIX, BINARY),
OP(CONDITIONAL_SUBSCRIPT, SUBSCRIPT, LEFT, INFIX, BINARY),
OP(CAST, CAST, LEFT, PREFIX, UNARY),
OP(USPLIT, SPLIT, LEFT, PREFIX, UNARY),
OP(UJOIN, JOIN, LEFT, PREFIX, UNARY),
OP(ARRAY_DELIMITER, ARRAY, LEFT, INFIX, BINARY),
OP(INCREMENT, INCREMENT, LEFT, INFIX, BINARY),
OP(LOGICAL_NOT, NOT, LEFT, PREFIX, UNARY),
OP(RANGE, RANGE, LEFT, INFIX, BINARY),
OP(FORMAT, FORMAT, LEFT, INFIX, BINARY),
OP(MULTIPLY, MULTIPLICATION, LEFT, INFIX, BINARY),
OP(DIVIDE, MULTIPLICATION, LEFT, INFIX, BINARY),
OP(MODULO, MULTIPLICATION, LEFT, INFIX, BINARY),
OP(ADD, ADDITION, LEFT, INFIX, BINARY),
OP(SUBTRACT, ADDITION, LEFT, INFIX, BINARY),
OP(BSPLIT, COMPARISON, LEFT, INFIX, BINARY),
OP(BJOIN, COMPARISON, LEFT, INFIX, BINARY),
OP(IS, COMPARISON, LEFT, INFIX, BINARY),
OP(ISNOT, COMPARISON, LEFT, INFIX, BINARY),
OP(AS, COMPARISON, LEFT, INFIX, BINARY),
OP(EQUAL, COMPARISON, LEFT, INFIX, BINARY),
OP(NOT_EQUAL, COMPARISON, LEFT, INFIX, BINARY),
OP(GREATER_THAN, COMPARISON, LEFT, INFIX, BINARY),
OP(LESS_THAN, COMPARISON, LEFT, INFIX, BINARY),
OP(GREATER_EQUAL, COMPARISON, LEFT, INFIX, BINARY),
OP(LESS_EQUAL, COMPARISON, LEFT, INFIX, BINARY),
OP(LIKE, COMPARISON, LEFT, INFIX, BINARY),
OP(NOTLIKE, COMPARISON, LEFT, INFIX, BINARY),
OP(MATCH, COMPARISON, LEFT, INFIX, BINARY),
OP(NOTMATCH, COMPARISON, LEFT, INFIX, BINARY),
OP(IN, COMPARISON, LEFT, INFIX, BINARY),
OP(NOTIN, COMPARISON, LEFT, INFIX, BINARY),
OP(CONTAINS, COMPARISON, LEFT, INFIX, BINARY),
OP(NOTCONTAINS, COMPARISON, LEFT, INFIX, BINARY),
OP(REPLACE, COMPARISON, LEFT, INFIX, BINARY),
OP(LOGICAL_AND, LOGICAL, LEFT, INFIX, BINARY),
OP(LOGICAL_OR, LOGICAL, LEFT, INFIX, BINARY),
OP(LOGICAL_XOR, LOGICAL, LEFT, INFIX, BINARY),
OP(BINARY_AND, BITWISE, LEFT, INFIX, BINARY),
OP(BINARY_OR, BITWISE, LEFT, INFIX, BINARY),
OP(BINARY_NOT, BITWISE, LEFT, INFIX, BINARY),
OP(BINARY_XOR, BITWISE, LEFT, INFIX, BINARY),
OP(LEFT_SHIFT, BITWISE, LEFT, INFIX, BINARY),
OP(RIGHT_SHIFT, BITWISE, LEFT, INFIX, BINARY),
OP(ASSIGN, ASSIGN, RIGHT, INFIX, BINARY),
OP(ADD_ASSIGN, ASSIGN, RIGHT, INFIX, BINARY),
OP(SUBTRACT_ASSIGN, ASSIGN, RIGHT, INFIX, BINARY),
OP(MULTIPLY_ASSIGN, ASSIGN, RIGHT, INFIX, BINARY),
OP(DIVIDE_ASSIGN, ASSIGN, RIGHT, INFIX, BINARY),
OP(MODULO_ASSIGN, ASSIGN, RIGHT, INFIX, BINARY),
/* these are not real operators, and are just used internally by the
* parser. */
OP(SUBEXPR, PARENTHESIS, LEFT, PREFIX, UNARY),
OP(ARRAY_START, PARENTHESIS, LEFT, PREFIX, UNARY),
OP(PAREN, PARENTHESIS, LEFT, PREFIX, UNARY),
OP(HASHTABLE_START, PARENTHESIS, LEFT, PREFIX, UNARY),
OP(SCRIPTBLOCK, PARENTHESIS, LEFT, PREFIX, UNARY),
};
static const size_t nr_operators = sizeof operators / sizeof operators[0];
static const struct bshell_operator_info *bshell_operator_symbols[] = {
BSHELL_SYM_OP(LOGICAL_NOT, BANG),
BSHELL_SYM_OP(ASSIGN, EQUAL),
BSHELL_SYM_OP(ADD, PLUS),
BSHELL_SYM_OP(SUBTRACT, HYPHEN),
BSHELL_SYM_OP(MULTIPLY, ASTERISK),
BSHELL_SYM_OP(DIVIDE, FORWARD_SLASH),
BSHELL_SYM_OP(MODULO, PERCENT),
BSHELL_SYM_OP(ADD_ASSIGN, PLUS_EQUAL),
BSHELL_SYM_OP(SUBTRACT_ASSIGN, HYPHEN_EQUAL),
BSHELL_SYM_OP(MULTIPLY_ASSIGN, ASTERISK_EQUAL),
BSHELL_SYM_OP(DIVIDE_ASSIGN, FORWARD_SLASH_EQUAL),
BSHELL_SYM_OP(MODULO_ASSIGN, PERCENT_EQUAL),
BSHELL_SYM_OP(RANGE, DOT_DOT),
BSHELL_SYM_OP(SUBSCRIPT, LEFT_BRACKET),
BSHELL_SYM_OP(CONDITIONAL_SUBSCRIPT, QUESTION_LEFT_BRACKET),
BSHELL_SYM_OP(ACCESS, DOT),
BSHELL_SYM_OP(CONDITIONAL_ACCESS, QUESTION_DOT),
BSHELL_SYM_OP(STATIC_ACCESS, COLON_COLON),
/* parser-internal pseudo-operators. */
/* CAST uses the same symbol as SUBSCRIPT */
/* BSHELL_SYM_OP(CAST, LEFT_BRACKET), */
BSHELL_SYM_OP(SUBEXPR, DOLLAR_LEFT_PAREN),
BSHELL_SYM_OP(PAREN, LEFT_PAREN),
BSHELL_SYM_OP(ARRAY_START, AT_LEFT_PAREN),
BSHELL_SYM_OP(HASHTABLE_START, AT_LEFT_BRACE),
};
static const size_t nr_bshell_operator_symbols = sizeof bshell_operator_symbols / sizeof bshell_operator_symbols[0];
static const struct bshell_operator_info *bshell_operator_token_ops[] = {
BSHELL_TKOP_OP(FORMAT, F),
BSHELL_TKOP_OP(BINARY_AND, BAND),
BSHELL_TKOP_OP(BINARY_OR, BOR),
BSHELL_TKOP_OP(BINARY_XOR, BXOR),
BSHELL_TKOP_OP(BINARY_NOT, BNOT),
BSHELL_TKOP_OP(LEFT_SHIFT, SHL),
BSHELL_TKOP_OP(RIGHT_SHIFT, SHR),
BSHELL_TKOP_OP(EQUAL, EQ),
BSHELL_TKOP_OP(NOT_EQUAL, NE),
BSHELL_TKOP_OP(GREATER_THAN, GT),
BSHELL_TKOP_OP(LESS_THAN, LT),
BSHELL_TKOP_OP(GREATER_EQUAL, GE),
BSHELL_TKOP_OP(LESS_EQUAL, LE),
BSHELL_TKOP_OP(MATCH, MATCH),
BSHELL_TKOP_OP(NOTMATCH, NOTMATCH),
BSHELL_TKOP_OP(REPLACE, REPLACE),
BSHELL_TKOP_OP(LIKE, LIKE),
BSHELL_TKOP_OP(NOTLIKE, NOTLIKE),
BSHELL_TKOP_OP(IN, IN),
BSHELL_TKOP_OP(NOTIN, NOTIN),
BSHELL_TKOP_OP(CONTAINS, CONTAINS),
BSHELL_TKOP_OP(NOTCONTAINS, NOTCONTAINS),
BSHELL_TKOP_OP(LOGICAL_AND, AND),
BSHELL_TKOP_OP(LOGICAL_OR, OR),
BSHELL_TKOP_OP(LOGICAL_XOR, XOR),
BSHELL_TKOP_OP(LOGICAL_NOT, NOT),
/* there are also unary versions of these operators */
BSHELL_TKOP_OP(BSPLIT, SPLIT),
BSHELL_TKOP_OP(BJOIN, JOIN),
BSHELL_TKOP_OP(IS, IS),
BSHELL_TKOP_OP(ISNOT, ISNOT),
BSHELL_TKOP_OP(AS, AS),
};
static const size_t nr_bshell_operator_token_ops = sizeof bshell_operator_token_ops / sizeof bshell_operator_token_ops[0];
/* clang-format on */
const struct bshell_operator_info *bshell_operator_get_by_token(
unsigned int token)
{
const struct bshell_operator_info **op_list = NULL;
size_t base = 0;
size_t op_list_size = 0;
if (token > __BSHELL_TKOP_INDEX_BASE
&& token < __BSHELL_TKOP_INDEX_LIMIT) {
op_list = bshell_operator_token_ops;
base = __BSHELL_TKOP_INDEX_BASE;
op_list_size = nr_bshell_operator_token_ops;
} else if (token > __BSHELL_SYM_INDEX_BASE && token < __BSHELL_SYM_INDEX_LIMIT) {
op_list = bshell_operator_symbols;
base = __BSHELL_SYM_INDEX_BASE;
op_list_size = nr_bshell_operator_symbols;
} else {
return NULL;
}
if (token - base >= op_list_size) {
return NULL;
}
return op_list[token - base];
}
const struct bshell_operator_info *bshell_operator_get_by_id(
enum bshell_operator_id id)
{
if (id >= nr_operators) {
return NULL;
}
const struct bshell_operator_info *op = &operators[id];
if (op->op_id != id) {
return NULL;
}
return op;
}
#define ENUM_STR(x) \
case x: \
return #x
const char *bshell_operator_id_to_string(enum bshell_operator_id op)
{
switch (op) {
ENUM_STR(BSHELL_OP_NONE);
ENUM_STR(BSHELL_OP_ADD);
ENUM_STR(BSHELL_OP_SUBTRACT);
ENUM_STR(BSHELL_OP_MULTIPLY);
ENUM_STR(BSHELL_OP_DIVIDE);
ENUM_STR(BSHELL_OP_MODULO);
ENUM_STR(BSHELL_OP_INCREMENT);
ENUM_STR(BSHELL_OP_DECREMENT);
ENUM_STR(BSHELL_OP_LEFT_SHIFT);
ENUM_STR(BSHELL_OP_RIGHT_SHIFT);
ENUM_STR(BSHELL_OP_BINARY_AND);
ENUM_STR(BSHELL_OP_BINARY_OR);
ENUM_STR(BSHELL_OP_BINARY_XOR);
ENUM_STR(BSHELL_OP_BINARY_NOT);
ENUM_STR(BSHELL_OP_LESS_THAN);
ENUM_STR(BSHELL_OP_GREATER_THAN);
ENUM_STR(BSHELL_OP_EQUAL);
ENUM_STR(BSHELL_OP_NOT_EQUAL);
ENUM_STR(BSHELL_OP_LESS_EQUAL);
ENUM_STR(BSHELL_OP_GREATER_EQUAL);
ENUM_STR(BSHELL_OP_ASSIGN);
ENUM_STR(BSHELL_OP_ADD_ASSIGN);
ENUM_STR(BSHELL_OP_SUBTRACT_ASSIGN);
ENUM_STR(BSHELL_OP_MULTIPLY_ASSIGN);
ENUM_STR(BSHELL_OP_DIVIDE_ASSIGN);
ENUM_STR(BSHELL_OP_MODULO_ASSIGN);
ENUM_STR(BSHELL_OP_LOGICAL_AND);
ENUM_STR(BSHELL_OP_LOGICAL_OR);
ENUM_STR(BSHELL_OP_LOGICAL_XOR);
ENUM_STR(BSHELL_OP_LOGICAL_NOT);
ENUM_STR(BSHELL_OP_RANGE);
ENUM_STR(BSHELL_OP_MATCH);
ENUM_STR(BSHELL_OP_NOTMATCH);
ENUM_STR(BSHELL_OP_REPLACE);
ENUM_STR(BSHELL_OP_LIKE);
ENUM_STR(BSHELL_OP_NOTLIKE);
ENUM_STR(BSHELL_OP_IN);
ENUM_STR(BSHELL_OP_NOTIN);
ENUM_STR(BSHELL_OP_FORMAT);
ENUM_STR(BSHELL_OP_CONTAINS);
ENUM_STR(BSHELL_OP_NOTCONTAINS);
ENUM_STR(BSHELL_OP_USPLIT);
ENUM_STR(BSHELL_OP_BSPLIT);
ENUM_STR(BSHELL_OP_UJOIN);
ENUM_STR(BSHELL_OP_BJOIN);
ENUM_STR(BSHELL_OP_IS);
ENUM_STR(BSHELL_OP_ISNOT);
ENUM_STR(BSHELL_OP_AS);
ENUM_STR(BSHELL_OP_SUBSCRIPT);
ENUM_STR(BSHELL_OP_CONDITIONAL_SUBSCRIPT);
ENUM_STR(BSHELL_OP_ARRAY_DELIMITER);
ENUM_STR(BSHELL_OP_ACCESS);
ENUM_STR(BSHELL_OP_STATIC_ACCESS);
ENUM_STR(BSHELL_OP_CONDITIONAL_ACCESS);
ENUM_STR(BSHELL_OP_CAST);
ENUM_STR(BSHELL_OP_SUBEXPR);
ENUM_STR(BSHELL_OP_PAREN);
ENUM_STR(BSHELL_OP_ARRAY_START);
ENUM_STR(BSHELL_OP_HASHTABLE_START);
default:
return "";
}
}