From 227e73853c1fc606d40b3028007183c38bf5ca32 Mon Sep 17 00:00:00 2001 From: Max Wash Date: Tue, 12 May 2026 22:57:42 +0100 Subject: [PATCH] parse: implement parsing of function definitions --- bshell/parse/syntax/func.c | 85 +++++++++++++++++++++++++++++++++++ bshell/parse/syntax/keyword.c | 21 +++++++++ 2 files changed, 106 insertions(+) create mode 100644 bshell/parse/syntax/func.c create mode 100644 bshell/parse/syntax/keyword.c diff --git a/bshell/parse/syntax/func.c b/bshell/parse/syntax/func.c new file mode 100644 index 0000000..85d670b --- /dev/null +++ b/bshell/parse/syntax/func.c @@ -0,0 +1,85 @@ +#include "../syntax.h" + +bool parse_func(struct parse_ctx *ctx, struct ast_node **out) +{ + if (!parse_keyword(ctx, KW_FUNC)) { + return false; + } + + struct lex_token *name = NULL; + if (!parse_word(ctx, &name)) { + report_error(ctx, "expected function identifier"); + return false; + } + + struct func_ast_node *func + = (struct func_ast_node *)ast_node_create(AST_FUNC); + if (!func) { + ctx->p_status = BSHELL_ERR_NO_MEMORY; + lex_token_destroy(name); + return false; + } + + func->n_name = name; + + if (!parse_symbol(ctx, SYM_LEFT_PAREN)) { + report_error(ctx, "expected `(` after function identifier"); + ast_node_destroy((struct ast_node *)func); + return false; + } + + size_t nr_args = 0; + bool ok = true; + while (1) { + if (parse_symbol(ctx, SYM_RIGHT_PAREN)) { + break; + } + + if (nr_args > 0 && !parse_symbol(ctx, SYM_COMMA)) { + report_error( + ctx, + "expected `,` or `)` after parameter name"); + ok = false; + break; + } + + struct lex_token *param_token = NULL; + struct var_ast_node *param_node = NULL; + if (!parse_var(ctx, ¶m_token)) { + report_error(ctx, "expected parameter variable"); + ok = false; + break; + } + + param_node = (struct var_ast_node *)ast_node_create(AST_VAR); + if (!param_node) { + ok = false; + ctx->p_status = BSHELL_ERR_NO_MEMORY; + lex_token_destroy(param_token); + 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; + } + + ast_node_destroy((struct ast_node *)func); + return false; + } + + if (!parse_block(ctx, &func->n_body)) { + report_error(ctx, "failed to parse function body"); + ast_node_destroy((struct ast_node *)func); + return false; + } + + *out = (struct ast_node *)func; + return true; +} diff --git a/bshell/parse/syntax/keyword.c b/bshell/parse/syntax/keyword.c new file mode 100644 index 0000000..3c285e1 --- /dev/null +++ b/bshell/parse/syntax/keyword.c @@ -0,0 +1,21 @@ +#include "../syntax.h" + +bool peek_keyword_expr(struct parse_ctx *ctx) +{ + return peek_unknown_keyword(ctx) != KW_NONE; +} + +bool parse_keyword_expr(struct parse_ctx *ctx, struct ast_node **out) +{ + switch (peek_unknown_keyword(ctx)) { + case KW_NONE: + return false; + case KW_IF: + return parse_if(ctx, out); + case KW_FUNC: + return parse_func(ctx, out); + default: + ctx->p_status = BSHELL_ERR_BAD_SYNTAX; + return false; + } +}