bshell: add ast node definitions
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
#include "ast.h"
|
||||
|
||||
#include "../status.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
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 "<unknown>";
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
#ifndef AST_H_
|
||||
#define AST_H_
|
||||
|
||||
#include "../status.h"
|
||||
|
||||
#include <fx/bstr.h>
|
||||
#include <fx/queue.h>
|
||||
|
||||
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
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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),
|
||||
};
|
||||
@@ -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),
|
||||
};
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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, " <expr>");
|
||||
} 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,
|
||||
};
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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,
|
||||
};
|
||||
Reference in New Issue
Block a user