From 090f6a0002bacf5c7202c165bbf5f6541f445388 Mon Sep 17 00:00:00 2001 From: Max Wash Date: Sat, 9 May 2026 18:59:13 +0100 Subject: [PATCH] bshell: add ast node definitions --- bshell/ast/ast.c | 166 +++++++++++++++++++++++++++++++++++++++ bshell/ast/ast.h | 126 +++++++++++++++++++++++++++++ bshell/ast/cmdcall.c | 31 ++++++++ bshell/ast/double.c | 6 ++ bshell/ast/fstring.c | 6 ++ bshell/ast/int.c | 14 ++++ bshell/ast/pipeline.c | 23 ++++++ bshell/ast/redirection.c | 43 ++++++++++ bshell/ast/string.c | 15 ++++ bshell/ast/var.c | 14 ++++ bshell/ast/word.c | 14 ++++ 11 files changed, 458 insertions(+) create mode 100644 bshell/ast/ast.c create mode 100644 bshell/ast/ast.h create mode 100644 bshell/ast/cmdcall.c create mode 100644 bshell/ast/double.c create mode 100644 bshell/ast/fstring.c create mode 100644 bshell/ast/int.c create mode 100644 bshell/ast/pipeline.c create mode 100644 bshell/ast/redirection.c create mode 100644 bshell/ast/string.c create mode 100644 bshell/ast/var.c create mode 100644 bshell/ast/word.c diff --git a/bshell/ast/ast.c b/bshell/ast/ast.c new file mode 100644 index 0000000..668b6b3 --- /dev/null +++ b/bshell/ast/ast.c @@ -0,0 +1,166 @@ +#include "ast.h" + +#include "../status.h" + +#include +#include +#include + +extern struct ast_node_definition int_ast_node; +extern struct ast_node_definition double_ast_node; +extern struct ast_node_definition word_ast_node; +extern struct ast_node_definition var_ast_node; +extern struct ast_node_definition string_ast_node; +extern struct ast_node_definition fstring_ast_node; +extern struct ast_node_definition cmdcall_ast_node; +extern struct ast_node_definition pipeline_ast_node; +extern struct ast_node_definition redirection_ast_node; + +static const struct ast_node_definition *ast_node_defintions[] = { + [AST_INT] = &int_ast_node, + [AST_DOUBLE] = &double_ast_node, + [AST_WORD] = &word_ast_node, + [AST_VAR] = &var_ast_node, + [AST_STRING] = &string_ast_node, + [AST_FSTRING] = &fstring_ast_node, + [AST_CMDCALL] = &cmdcall_ast_node, + [AST_PIPELINE] = &pipeline_ast_node, + [AST_REDIRECTION] = &redirection_ast_node, +}; +static const size_t nr_ast_node_definitions + = sizeof ast_node_defintions / sizeof ast_node_defintions[0]; + +struct ast_node *ast_node_create(enum ast_node_type type) +{ + assert(type < nr_ast_node_definitions); + + const struct ast_node_definition *def = ast_node_defintions[type]; + struct ast_node *out = malloc(def->def_node_size); + if (!out) { + return NULL; + } + + memset(out, 0x0, def->def_node_size); + + out->n_type = type; + + return out; +} + +void ast_node_destroy(struct ast_node *node) +{ + assert(node->n_type < nr_ast_node_definitions); + + struct ast_iterator it = {0}; + ast_iterator_enqueue(&it, node); + + while (1) { + node = ast_iterator_peek(&it); + if (!node) { + break; + } + + const struct ast_node_definition *def + = ast_node_defintions[node->n_type]; + + if (def->def_cleanup) { + def->def_cleanup(node); + } + + ast_iterator_dequeue(&it); + free(node); + } +} + +void ast_node_iterate(struct ast_node *node, struct ast_iterator *it) +{ + ast_iterator_enqueue(it, node); +} + +void ast_node_to_string(const struct ast_node *node, fx_bstr *out) +{ + const struct ast_node_definition *def + = ast_node_defintions[node->n_type]; + if (def->def_to_string) { + def->def_to_string(node, out); + } +} + +#define ENUM_STR(x) \ + case x: \ + return #x + +const char *ast_node_type_to_string(enum ast_node_type type) +{ + switch (type) { + ENUM_STR(AST_NONE); + ENUM_STR(AST_INT); + ENUM_STR(AST_DOUBLE); + ENUM_STR(AST_WORD); + ENUM_STR(AST_STRING); + ENUM_STR(AST_FSTRING); + ENUM_STR(AST_VAR); + ENUM_STR(AST_VAR_SPLAT); + ENUM_STR(AST_FLAG); + ENUM_STR(AST_CMDCALL); + ENUM_STR(AST_PIPELINE); + ENUM_STR(AST_REDIRECTION); + default: + return ""; + } +} + +struct ast_node *ast_iterator_peek(struct ast_iterator *it) +{ + fx_queue_entry *cur = fx_queue_first(&it->it_queue); + if (!cur) { + return NULL; + } + + return fx_unbox(struct ast_node, cur, n_it.e_entry); +} + +struct ast_node *ast_iterator_dequeue(struct ast_iterator *it) +{ + fx_queue_entry *cur = fx_queue_first(&it->it_queue); + if (!cur) { + return NULL; + } + + struct ast_node *node = fx_unbox(struct ast_node, cur, n_it.e_entry); + const struct ast_node_definition *def + = ast_node_defintions[node->n_type]; + + it->it_insert_after = cur; + if (def->def_collect_children) { + def->def_collect_children(node, it); + } + + fx_queue_pop_front(&it->it_queue); + return fx_unbox(struct ast_node, cur, n_it.e_entry); +} + +void ast_iterator_enqueue(struct ast_iterator *it, struct ast_node *node) +{ + unsigned long new_depth = 0; + + fx_queue_entry *cur = fx_queue_first(&it->it_queue); + if (cur) { + struct ast_node *cur_node + = fx_unbox(struct ast_node, cur, n_it.e_entry); + new_depth = cur_node->n_it.e_depth + 1; + } + + node->n_it.e_depth = new_depth; + + if (!it->it_insert_after) { + fx_queue_push_back(&it->it_queue, &node->n_it.e_entry); + return; + } + + fx_queue_insert_after( + &it->it_queue, + &node->n_it.e_entry, + it->it_insert_after); + it->it_insert_after = &node->n_it.e_entry; +} diff --git a/bshell/ast/ast.h b/bshell/ast/ast.h new file mode 100644 index 0000000..5cc2d44 --- /dev/null +++ b/bshell/ast/ast.h @@ -0,0 +1,126 @@ +#ifndef AST_H_ +#define AST_H_ + +#include "../status.h" + +#include +#include + +struct lex_token; + +enum ast_node_type { + AST_NONE = 0x00u, + AST_INT, + AST_DOUBLE, + AST_WORD, + AST_STRING, + AST_FSTRING, + AST_VAR, + AST_VAR_SPLAT, + AST_FLAG, + AST_CMDCALL, + AST_PIPELINE, + AST_REDIRECTION, +}; + +struct ast_iterator_entry { + fx_queue_entry e_entry; + unsigned long e_depth; +}; + +struct ast_node { + enum ast_node_type n_type; + struct ast_node *n_parent; + fx_queue_entry n_entry; + struct ast_iterator_entry n_it; +}; + +struct int_ast_node { + struct ast_node n_base; + struct lex_token *n_value; +}; + +struct double_ast_node { + struct ast_node n_base; + struct lex_token *n_value; +}; + +struct word_ast_node { + struct ast_node n_base; + struct lex_token *n_value; +}; + +struct string_ast_node { + struct ast_node n_base; + struct lex_token *n_value; +}; + +struct fstring_ast_node { + struct ast_node n_base; + fx_queue n_elements; +}; + +struct var_ast_node { + struct ast_node n_base; + struct lex_token *n_ident; +}; + +struct var_splat_ast_node { + struct ast_node n_base; + struct lex_token *n_ident; +}; + +struct cmdcall_ast_node { + struct ast_node n_base; + fx_queue n_args; + fx_queue n_redirect; +}; + +struct pipeline_ast_node { + struct ast_node n_base; + fx_queue n_stages; +}; + +struct redirection_ast_node { + struct ast_node n_base; + bool n_append : 1; + bool n_out_is_fd : 1; + bool n_out_is_expr : 1; + + unsigned int n_in, n_out; + struct ast_node *n_out_path_expr; + const char *n_out_path; + struct lex_token *n_out_tok; +}; + +struct ast_iterator { + struct ast_node *it_cur; + fx_queue it_queue; + unsigned int it_depth; + fx_queue_entry *it_insert_after; +}; + +struct ast_node_definition { + enum ast_node_type def_id; + size_t def_node_size; + enum bshell_status (*def_collect_children)( + struct ast_node *, + struct ast_iterator *); + enum bshell_status (*def_cleanup)(struct ast_node *); + void (*def_to_string)(const struct ast_node *, fx_bstr *); +}; + +extern struct ast_node *ast_node_create(enum ast_node_type type); +extern void ast_node_destroy(struct ast_node *node); +extern void ast_node_iterate(struct ast_node *node, struct ast_iterator *it); +extern void ast_node_to_string(const struct ast_node *node, fx_bstr *out); + +extern const char *ast_node_type_to_string(enum ast_node_type type); + +extern struct ast_node *ast_iterator_peek(struct ast_iterator *it); +extern struct ast_node *ast_iterator_dequeue(struct ast_iterator *it); +extern void ast_iterator_enqueue( + struct ast_iterator *it, + struct ast_node *node); + +#endif diff --git a/bshell/ast/cmdcall.c b/bshell/ast/cmdcall.c new file mode 100644 index 0000000..b895843 --- /dev/null +++ b/bshell/ast/cmdcall.c @@ -0,0 +1,31 @@ +#include "ast.h" + +static enum bshell_status collect_children( + struct ast_node *node, + struct ast_iterator *it) +{ + struct cmdcall_ast_node *cmdcall = (struct cmdcall_ast_node *)node; + fx_queue_entry *cur = fx_queue_first(&cmdcall->n_args); + while (cur) { + struct ast_node *child + = fx_unbox(struct ast_node, cur, n_entry); + ast_iterator_enqueue(it, child); + cur = fx_queue_next(cur); + } + + cur = fx_queue_first(&cmdcall->n_redirect); + while (cur) { + struct ast_node *child + = fx_unbox(struct ast_node, cur, n_entry); + ast_iterator_enqueue(it, child); + cur = fx_queue_next(cur); + } + + return BSHELL_SUCCESS; +} + +struct ast_node_definition cmdcall_ast_node = { + .def_id = AST_CMDCALL, + .def_node_size = sizeof(struct cmdcall_ast_node), + .def_collect_children = collect_children, +}; diff --git a/bshell/ast/double.c b/bshell/ast/double.c new file mode 100644 index 0000000..1f79e6b --- /dev/null +++ b/bshell/ast/double.c @@ -0,0 +1,6 @@ +#include "ast.h" + +struct ast_node_definition double_ast_node = { + .def_id = AST_DOUBLE, + .def_node_size = sizeof(struct double_ast_node), +}; diff --git a/bshell/ast/fstring.c b/bshell/ast/fstring.c new file mode 100644 index 0000000..687436f --- /dev/null +++ b/bshell/ast/fstring.c @@ -0,0 +1,6 @@ +#include "ast.h" + +struct ast_node_definition fstring_ast_node = { + .def_id = AST_FSTRING, + .def_node_size = sizeof(struct fstring_ast_node), +}; diff --git a/bshell/ast/int.c b/bshell/ast/int.c new file mode 100644 index 0000000..0cafd4c --- /dev/null +++ b/bshell/ast/int.c @@ -0,0 +1,14 @@ +#include "../parse/token.h" +#include "ast.h" + +static void to_string(const struct ast_node *node, fx_bstr *out) +{ + struct int_ast_node *i = (struct int_ast_node *)node; + fx_bstr_write_fmt(out, NULL, "%lld", i->n_value->tok_int); +} + +struct ast_node_definition int_ast_node = { + .def_id = AST_INT, + .def_node_size = sizeof(struct int_ast_node), + .def_to_string = to_string, +}; diff --git a/bshell/ast/pipeline.c b/bshell/ast/pipeline.c new file mode 100644 index 0000000..25f432b --- /dev/null +++ b/bshell/ast/pipeline.c @@ -0,0 +1,23 @@ +#include "ast.h" + +static enum bshell_status collect_children( + struct ast_node *node, + struct ast_iterator *it) +{ + struct pipeline_ast_node *pipeline = (struct pipeline_ast_node *)node; + fx_queue_entry *cur = fx_queue_first(&pipeline->n_stages); + while (cur) { + struct ast_node *child + = fx_unbox(struct ast_node, cur, n_entry); + ast_iterator_enqueue(it, child); + cur = fx_queue_next(cur); + } + + return BSHELL_SUCCESS; +} + +struct ast_node_definition pipeline_ast_node = { + .def_id = AST_PIPELINE, + .def_node_size = sizeof(struct pipeline_ast_node), + .def_collect_children = collect_children, +}; diff --git a/bshell/ast/redirection.c b/bshell/ast/redirection.c new file mode 100644 index 0000000..88994d0 --- /dev/null +++ b/bshell/ast/redirection.c @@ -0,0 +1,43 @@ +#include "ast.h" + +static enum bshell_status collect_children( + struct ast_node *node, + struct ast_iterator *it) +{ + struct redirection_ast_node *redirection + = (struct redirection_ast_node *)node; + + if (redirection->n_out_path_expr) { + ast_iterator_enqueue(it, redirection->n_out_path_expr); + } + + return BSHELL_SUCCESS; +} + +static void to_string(const struct ast_node *node, fx_bstr *out) +{ + struct redirection_ast_node *redirection + = (struct redirection_ast_node *)node; + fx_bstr_write_fmt(out, NULL, "&%u", redirection->n_in); + + if (redirection->n_append) { + fx_bstr_write_fmt(out, NULL, " >>"); + } else { + fx_bstr_write_fmt(out, NULL, " >"); + } + + if (redirection->n_out_is_fd) { + fx_bstr_write_fmt(out, NULL, " &%u", redirection->n_out); + } else if (redirection->n_out_is_expr) { + fx_bstr_write_fmt(out, NULL, " "); + } else { + fx_bstr_write_fmt(out, NULL, " '%s'", redirection->n_out_path); + } +} + +struct ast_node_definition redirection_ast_node = { + .def_id = AST_REDIRECTION, + .def_node_size = sizeof(struct redirection_ast_node), + .def_collect_children = collect_children, + .def_to_string = to_string, +}; diff --git a/bshell/ast/string.c b/bshell/ast/string.c new file mode 100644 index 0000000..dba76e4 --- /dev/null +++ b/bshell/ast/string.c @@ -0,0 +1,15 @@ +#include "../parse/token.h" +#include "ast.h" + +static void to_string(const struct ast_node *node, fx_bstr *out) +{ + const struct string_ast_node *string + = (const struct string_ast_node *)node; + fx_bstr_write_fmt(out, NULL, "%s", string->n_value->tok_str); +} + +struct ast_node_definition string_ast_node = { + .def_id = AST_STRING, + .def_node_size = sizeof(struct string_ast_node), + .def_to_string = to_string, +}; diff --git a/bshell/ast/var.c b/bshell/ast/var.c new file mode 100644 index 0000000..75d7401 --- /dev/null +++ b/bshell/ast/var.c @@ -0,0 +1,14 @@ +#include "../parse/token.h" +#include "ast.h" + +static void to_string(const struct ast_node *node, fx_bstr *out) +{ + const struct var_ast_node *var = (const struct var_ast_node *)node; + fx_bstr_write_fmt(out, NULL, "%s", var->n_ident->tok_str); +} + +struct ast_node_definition var_ast_node = { + .def_id = AST_VAR, + .def_node_size = sizeof(struct var_ast_node), + .def_to_string = to_string, +}; diff --git a/bshell/ast/word.c b/bshell/ast/word.c new file mode 100644 index 0000000..af57db3 --- /dev/null +++ b/bshell/ast/word.c @@ -0,0 +1,14 @@ +#include "../parse/token.h" +#include "ast.h" + +static void to_string(const struct ast_node *node, fx_bstr *out) +{ + const struct word_ast_node *word = (const struct word_ast_node *)node; + fx_bstr_write_fmt(out, NULL, "%s", word->n_value->tok_str); +} + +struct ast_node_definition word_ast_node = { + .def_id = AST_WORD, + .def_node_size = sizeof(struct word_ast_node), + .def_to_string = to_string, +};