2026-05-12 22:57:42 +01:00
|
|
|
#include "../syntax.h"
|
|
|
|
|
|
2026-05-25 10:33:29 +01:00
|
|
|
bool parse_func(struct bshell_parse_ctx *ctx, struct bshell_ast_node **out)
|
2026-05-12 22:57:42 +01:00
|
|
|
{
|
2026-05-25 10:33:29 +01:00
|
|
|
if (!parse_keyword(ctx, BSHELL_KW_FUNC)) {
|
2026-05-12 22:57:42 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-25 10:33:29 +01:00
|
|
|
struct bshell_lex_token *name = NULL;
|
2026-05-12 22:57:42 +01:00
|
|
|
if (!parse_word(ctx, &name)) {
|
|
|
|
|
report_error(ctx, "expected function identifier");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-25 10:33:29 +01:00
|
|
|
struct bshell_func_ast_node *func
|
|
|
|
|
= (struct bshell_func_ast_node *)bshell_ast_node_create(
|
|
|
|
|
BSHELL_AST_FUNC);
|
2026-05-12 22:57:42 +01:00
|
|
|
if (!func) {
|
|
|
|
|
ctx->p_status = BSHELL_ERR_NO_MEMORY;
|
2026-05-25 10:33:29 +01:00
|
|
|
bshell_lex_token_destroy(name);
|
2026-05-12 22:57:42 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func->n_name = name;
|
|
|
|
|
|
2026-05-25 10:33:29 +01:00
|
|
|
if (!parse_symbol(ctx, BSHELL_SYM_LEFT_PAREN)) {
|
2026-05-12 22:57:42 +01:00
|
|
|
report_error(ctx, "expected `(` after function identifier");
|
2026-05-25 10:33:29 +01:00
|
|
|
bshell_ast_node_destroy((struct bshell_ast_node *)func);
|
2026-05-12 22:57:42 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t nr_args = 0;
|
|
|
|
|
bool ok = true;
|
|
|
|
|
while (1) {
|
2026-05-25 10:33:29 +01:00
|
|
|
if (parse_symbol(ctx, BSHELL_SYM_RIGHT_PAREN)) {
|
2026-05-12 22:57:42 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-25 10:33:29 +01:00
|
|
|
if (nr_args > 0 && !parse_symbol(ctx, BSHELL_SYM_COMMA)) {
|
2026-05-12 22:57:42 +01:00
|
|
|
report_error(
|
|
|
|
|
ctx,
|
|
|
|
|
"expected `,` or `)` after parameter name");
|
|
|
|
|
ok = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-25 10:33:29 +01:00
|
|
|
struct bshell_lex_token *param_token = NULL;
|
|
|
|
|
struct bshell_var_ast_node *param_node = NULL;
|
2026-05-12 22:57:42 +01:00
|
|
|
if (!parse_var(ctx, ¶m_token)) {
|
|
|
|
|
report_error(ctx, "expected parameter variable");
|
|
|
|
|
ok = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-25 10:33:29 +01:00
|
|
|
param_node
|
|
|
|
|
= (struct bshell_var_ast_node *)bshell_ast_node_create(
|
|
|
|
|
BSHELL_AST_VAR);
|
2026-05-12 22:57:42 +01:00
|
|
|
if (!param_node) {
|
|
|
|
|
ok = false;
|
|
|
|
|
ctx->p_status = BSHELL_ERR_NO_MEMORY;
|
2026-05-25 10:33:29 +01:00
|
|
|
bshell_lex_token_destroy(param_token);
|
2026-05-12 22:57:42 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
param_node->n_ident = param_token;
|
|
|
|
|
fx_queue_push_back(
|
|
|
|
|
&func->n_params,
|
|
|
|
|
¶m_node->n_base.n_entry);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!ok) {
|
|
|
|
|
if (ctx->p_status == BSHELL_SUCCESS) {
|
|
|
|
|
ctx->p_status = BSHELL_ERR_BAD_SYNTAX;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-25 10:33:29 +01:00
|
|
|
bshell_ast_node_destroy((struct bshell_ast_node *)func);
|
2026-05-12 22:57:42 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!parse_block(ctx, &func->n_body)) {
|
|
|
|
|
report_error(ctx, "failed to parse function body");
|
2026-05-25 10:33:29 +01:00
|
|
|
bshell_ast_node_destroy((struct bshell_ast_node *)func);
|
2026-05-12 22:57:42 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-25 10:33:29 +01:00
|
|
|
*out = (struct bshell_ast_node *)func;
|
2026-05-12 22:57:42 +01:00
|
|
|
return true;
|
|
|
|
|
}
|