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
This commit is contained in:
@@ -0,0 +1,277 @@
|
||||
#include <assert.h>
|
||||
#include <bshell/ast.h>
|
||||
#include <bshell/status.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
extern struct bshell_ast_node_definition null_bshell_ast_node;
|
||||
extern struct bshell_ast_node_definition int_bshell_ast_node;
|
||||
extern struct bshell_ast_node_definition double_bshell_ast_node;
|
||||
extern struct bshell_ast_node_definition word_bshell_ast_node;
|
||||
extern struct bshell_ast_node_definition var_bshell_ast_node;
|
||||
extern struct bshell_ast_node_definition string_bshell_ast_node;
|
||||
extern struct bshell_ast_node_definition fstring_bshell_ast_node;
|
||||
extern struct bshell_ast_node_definition cmdcall_bshell_ast_node;
|
||||
extern struct bshell_ast_node_definition pipeline_bshell_ast_node;
|
||||
extern struct bshell_ast_node_definition redirection_bshell_ast_node;
|
||||
extern struct bshell_ast_node_definition block_bshell_ast_node;
|
||||
extern struct bshell_ast_node_definition stmt_list_bshell_ast_node;
|
||||
extern struct bshell_ast_node_definition func_bshell_ast_node;
|
||||
extern struct bshell_ast_node_definition array_bshell_ast_node;
|
||||
extern struct bshell_ast_node_definition hashtable_bshell_ast_node;
|
||||
extern struct bshell_ast_node_definition hashtable_item_bshell_ast_node;
|
||||
extern struct bshell_ast_node_definition if_bshell_ast_node;
|
||||
extern struct bshell_ast_node_definition if_branch_bshell_ast_node;
|
||||
extern struct bshell_ast_node_definition op_bshell_ast_node;
|
||||
|
||||
static const struct bshell_ast_node_definition *bshell_ast_node_definitions[]
|
||||
= {
|
||||
[BSHELL_AST_NULL] = &null_bshell_ast_node,
|
||||
[BSHELL_AST_INT] = &int_bshell_ast_node,
|
||||
[BSHELL_AST_DOUBLE] = &double_bshell_ast_node,
|
||||
[BSHELL_AST_WORD] = &word_bshell_ast_node,
|
||||
[BSHELL_AST_VAR] = &var_bshell_ast_node,
|
||||
[BSHELL_AST_STRING] = &string_bshell_ast_node,
|
||||
[BSHELL_AST_FSTRING] = &fstring_bshell_ast_node,
|
||||
[BSHELL_AST_CMDCALL] = &cmdcall_bshell_ast_node,
|
||||
[BSHELL_AST_PIPELINE] = &pipeline_bshell_ast_node,
|
||||
[BSHELL_AST_REDIRECTION] = &redirection_bshell_ast_node,
|
||||
[BSHELL_AST_BLOCK] = &block_bshell_ast_node,
|
||||
[BSHELL_AST_STMT_LIST] = &stmt_list_bshell_ast_node,
|
||||
[BSHELL_AST_FUNC] = &func_bshell_ast_node,
|
||||
[BSHELL_AST_ARRAY] = &array_bshell_ast_node,
|
||||
[BSHELL_AST_IF] = &if_bshell_ast_node,
|
||||
[BSHELL_AST_IF_BRANCH] = &if_branch_bshell_ast_node,
|
||||
[BSHELL_AST_HASHTABLE] = &hashtable_bshell_ast_node,
|
||||
[BSHELL_AST_HASHTABLE_ITEM] = &hashtable_item_bshell_ast_node,
|
||||
[BSHELL_AST_OP] = &op_bshell_ast_node,
|
||||
};
|
||||
static const size_t nr_bshell_ast_node_definitions
|
||||
= sizeof bshell_ast_node_definitions
|
||||
/ sizeof bshell_ast_node_definitions[0];
|
||||
|
||||
struct bshell_ast_node *bshell_ast_node_create(enum bshell_ast_node_type type)
|
||||
{
|
||||
assert(type < nr_bshell_ast_node_definitions);
|
||||
|
||||
const struct bshell_ast_node_definition *def
|
||||
= bshell_ast_node_definitions[type];
|
||||
struct bshell_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 bshell_ast_node_destroy(struct bshell_ast_node *node)
|
||||
{
|
||||
assert(node->n_type < nr_bshell_ast_node_definitions);
|
||||
|
||||
struct bshell_ast_iterator it = {0};
|
||||
bshell_ast_iterator_enqueue(&it, node);
|
||||
|
||||
while (1) {
|
||||
node = bshell_ast_iterator_peek(&it);
|
||||
if (!node) {
|
||||
break;
|
||||
}
|
||||
|
||||
const struct bshell_ast_node_definition *def
|
||||
= bshell_ast_node_definitions[node->n_type];
|
||||
|
||||
if (def->def_cleanup) {
|
||||
def->def_cleanup(node);
|
||||
}
|
||||
|
||||
bshell_ast_iterator_dequeue(&it);
|
||||
free(node);
|
||||
}
|
||||
}
|
||||
|
||||
void bshell_ast_node_to_string(const struct bshell_ast_node *node, fx_bstr *out)
|
||||
{
|
||||
const struct bshell_ast_node_definition *def
|
||||
= bshell_ast_node_definitions[node->n_type];
|
||||
if (def->def_to_string) {
|
||||
def->def_to_string(node, out);
|
||||
}
|
||||
}
|
||||
|
||||
#define ENUM_STR(x) \
|
||||
case x: \
|
||||
return #x
|
||||
|
||||
const char *bshell_ast_node_type_to_string(enum bshell_ast_node_type type)
|
||||
{
|
||||
switch (type) {
|
||||
ENUM_STR(BSHELL_AST_NONE);
|
||||
ENUM_STR(BSHELL_AST_NULL);
|
||||
ENUM_STR(BSHELL_AST_STMT_LIST);
|
||||
ENUM_STR(BSHELL_AST_INT);
|
||||
ENUM_STR(BSHELL_AST_DOUBLE);
|
||||
ENUM_STR(BSHELL_AST_WORD);
|
||||
ENUM_STR(BSHELL_AST_STRING);
|
||||
ENUM_STR(BSHELL_AST_FSTRING);
|
||||
ENUM_STR(BSHELL_AST_VAR);
|
||||
ENUM_STR(BSHELL_AST_VAR_SPLAT);
|
||||
ENUM_STR(BSHELL_AST_FLAG);
|
||||
ENUM_STR(BSHELL_AST_CMDCALL);
|
||||
ENUM_STR(BSHELL_AST_PIPELINE);
|
||||
ENUM_STR(BSHELL_AST_REDIRECTION);
|
||||
ENUM_STR(BSHELL_AST_BLOCK);
|
||||
ENUM_STR(BSHELL_AST_FUNC);
|
||||
ENUM_STR(BSHELL_AST_IF);
|
||||
ENUM_STR(BSHELL_AST_IF_BRANCH);
|
||||
ENUM_STR(BSHELL_AST_OP);
|
||||
ENUM_STR(BSHELL_AST_ARRAY);
|
||||
ENUM_STR(BSHELL_AST_HASHTABLE);
|
||||
ENUM_STR(BSHELL_AST_HASHTABLE_ITEM);
|
||||
default:
|
||||
return "<unknown>";
|
||||
}
|
||||
}
|
||||
|
||||
struct bshell_ast_node *bshell_ast_iterator_peek(struct bshell_ast_iterator *it)
|
||||
{
|
||||
fx_queue_entry *cur = fx_queue_first(&it->it_queue);
|
||||
if (!cur) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return fx_unbox(struct bshell_ast_node, cur, n_it.e_entry);
|
||||
}
|
||||
|
||||
struct bshell_ast_node *bshell_ast_iterator_dequeue(
|
||||
struct bshell_ast_iterator *it)
|
||||
{
|
||||
fx_queue_entry *cur = fx_queue_first(&it->it_queue);
|
||||
if (!cur) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct bshell_ast_node *node = fx_unbox(
|
||||
struct bshell_ast_node,
|
||||
cur,
|
||||
n_it.e_entry);
|
||||
const struct bshell_ast_node_definition *def
|
||||
= bshell_ast_node_definitions[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 bshell_ast_node, cur, n_it.e_entry);
|
||||
}
|
||||
|
||||
void bshell_ast_iterator_enqueue(
|
||||
struct bshell_ast_iterator *it,
|
||||
struct bshell_ast_node *node)
|
||||
{
|
||||
unsigned long new_depth = 0;
|
||||
|
||||
fx_queue_entry *cur = fx_queue_first(&it->it_queue);
|
||||
if (cur) {
|
||||
struct bshell_ast_node *cur_node = fx_unbox(
|
||||
struct bshell_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;
|
||||
}
|
||||
|
||||
enum bshell_status bshell_ast_node_iterate(
|
||||
struct bshell_ast_node *node,
|
||||
struct bshell_ast_iterator *it,
|
||||
bshell_ast_iterator_callback callback,
|
||||
void *arg)
|
||||
{
|
||||
fx_queue_push_back(&it->it_queue, &node->n_it.e_entry);
|
||||
node->n_it.e_depth = 0;
|
||||
|
||||
fx_queue_entry *entry = fx_queue_first(&it->it_queue);
|
||||
|
||||
while (entry) {
|
||||
struct bshell_ast_iterator_entry *it_entry = fx_unbox(
|
||||
struct bshell_ast_iterator_entry,
|
||||
entry,
|
||||
e_entry);
|
||||
node = fx_unbox(struct bshell_ast_node, it_entry, n_it);
|
||||
|
||||
if (!node) {
|
||||
/* this should never happen. */
|
||||
return BSHELL_ERR_INTERNAL_FAILURE;
|
||||
}
|
||||
|
||||
struct bshell_ast_iterate_result result = callback(
|
||||
node,
|
||||
BSHELL_AST_ITERATION_PRE,
|
||||
it,
|
||||
arg);
|
||||
if (result.r_status != BSHELL_SUCCESS
|
||||
|| result.r_flags & BSHELL_AST_ITERATE_STOP) {
|
||||
return result.r_status;
|
||||
}
|
||||
|
||||
const struct bshell_ast_node_definition *type
|
||||
= bshell_ast_node_definitions[node->n_type];
|
||||
if (type->def_collect_children
|
||||
&& result.r_flags & BSHELL_AST_ITERATE_ADD_CHILDREN) {
|
||||
it->it_insert_after = entry;
|
||||
type->def_collect_children(node, it);
|
||||
}
|
||||
|
||||
if (!(result.r_flags & BSHELL_AST_ITERATE_REPEAT)) {
|
||||
entry = fx_queue_next(entry);
|
||||
}
|
||||
}
|
||||
|
||||
while (!fx_queue_empty(&it->it_queue)) {
|
||||
fx_queue_entry *entry = fx_queue_last(&it->it_queue);
|
||||
if (!entry) {
|
||||
break;
|
||||
}
|
||||
|
||||
node = fx_unbox(struct bshell_ast_node, entry, n_it);
|
||||
|
||||
if (!node) {
|
||||
/* this should never happen. */
|
||||
return BSHELL_ERR_INTERNAL_FAILURE;
|
||||
}
|
||||
|
||||
struct bshell_ast_iterate_result result = callback(
|
||||
node,
|
||||
BSHELL_AST_ITERATION_POST,
|
||||
it,
|
||||
arg);
|
||||
if (result.r_status != BSHELL_SUCCESS
|
||||
|| result.r_flags & BSHELL_AST_ITERATE_STOP) {
|
||||
return result.r_status;
|
||||
}
|
||||
|
||||
if (!(result.r_flags & BSHELL_AST_ITERATE_REPEAT)) {
|
||||
fx_queue_pop_back(&it->it_queue);
|
||||
}
|
||||
}
|
||||
|
||||
return BSHELL_SUCCESS;
|
||||
}
|
||||
Reference in New Issue
Block a user