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,25 @@
|
||||
#include "compile-node.h"
|
||||
|
||||
static const struct compile_value_type array_type = {};
|
||||
static const struct compile_value_type array_item_type = {};
|
||||
|
||||
struct compile_result compile_array(
|
||||
struct compile_ctx *ctx,
|
||||
struct bshell_ast_node *src)
|
||||
{
|
||||
struct bshell_array_ast_node *array;
|
||||
array = (struct bshell_array_ast_node *)src;
|
||||
size_t nr_items = fx_queue_length(&array->n_items);
|
||||
for (size_t i = 0; i < nr_items; i++) {
|
||||
struct compile_value *item = compile_pop_value(ctx);
|
||||
compile_value_load(ctx, item);
|
||||
compile_value_destroy(item);
|
||||
}
|
||||
|
||||
bshell_scriptblock_push_instruction(
|
||||
ctx->c_block,
|
||||
BSHELL_OPCODE_MK_ARRAY,
|
||||
nr_items);
|
||||
compile_push_value(ctx, &array_type, src);
|
||||
return COMPILE_OK(0);
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
#include "compile-node.h"
|
||||
|
||||
#include <bshell/compile.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static enum bshell_status block_load(
|
||||
struct compile_ctx *ctx,
|
||||
struct compile_value *value)
|
||||
{
|
||||
bshell_scriptblock_push_instruction(
|
||||
ctx->c_block,
|
||||
BSHELL_OPCODE_LDBLOCK,
|
||||
value->v_pool);
|
||||
return BSHELL_SUCCESS;
|
||||
}
|
||||
|
||||
static const struct compile_value_type block_type = {
|
||||
.v_load = block_load,
|
||||
};
|
||||
|
||||
struct compile_result compile_block(
|
||||
struct compile_ctx *ctx,
|
||||
struct bshell_ast_node *src)
|
||||
{
|
||||
bshell_scriptblock *sub_block = bshell_scriptblock_create();
|
||||
if (!sub_block) {
|
||||
return COMPILE_ERR(BSHELL_ERR_NO_MEMORY);
|
||||
}
|
||||
|
||||
enum bshell_status status = bshell_compile(src, sub_block);
|
||||
if (status != BSHELL_SUCCESS) {
|
||||
bshell_scriptblock_unref(sub_block);
|
||||
return COMPILE_ERR(status);
|
||||
}
|
||||
|
||||
fx_value sub_block_value = FX_VALUE_OBJECT(sub_block);
|
||||
unsigned long slot = bshell_scriptblock_add_pool_value(
|
||||
ctx->c_block,
|
||||
&sub_block_value);
|
||||
fx_value_unset(&sub_block_value);
|
||||
compile_push_pool_value(ctx, &block_type, slot);
|
||||
|
||||
return COMPILE_OK(0);
|
||||
}
|
||||
|
||||
enum bshell_status compile_block_immediate(
|
||||
struct compile_ctx *ctx,
|
||||
struct bshell_ast_node *src)
|
||||
{
|
||||
enum bshell_status status = BSHELL_SUCCESS;
|
||||
struct bshell_block_ast_node *block = (struct bshell_block_ast_node *)
|
||||
src;
|
||||
|
||||
fx_queue_entry *cur = fx_queue_first(&block->n_statements);
|
||||
while (cur && status == BSHELL_SUCCESS) {
|
||||
struct bshell_ast_node *node = fx_unbox(
|
||||
struct bshell_ast_node,
|
||||
cur,
|
||||
n_entry);
|
||||
status = compile_node(ctx, node);
|
||||
cur = fx_queue_next(cur);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
#include "compile-node.h"
|
||||
|
||||
enum bshell_status cmdcall_load(
|
||||
struct compile_ctx *ctx,
|
||||
struct compile_value *value)
|
||||
{
|
||||
struct bshell_cmdcall_ast_node *cmdcall;
|
||||
cmdcall = (struct bshell_cmdcall_ast_node *)value->v_node;
|
||||
bshell_scriptblock_push_instruction(ctx->c_block, BSHELL_OPCODE_PEXEC, 1);
|
||||
return BSHELL_SUCCESS;
|
||||
}
|
||||
|
||||
enum bshell_status pipeline_load(
|
||||
struct compile_ctx *ctx,
|
||||
struct compile_value *value)
|
||||
{
|
||||
struct bshell_pipeline_ast_node *pipeline;
|
||||
pipeline = (struct bshell_pipeline_ast_node *)value->v_node;
|
||||
size_t nr_items = fx_queue_length(&pipeline->n_stages);
|
||||
bshell_scriptblock_push_instruction(
|
||||
ctx->c_block,
|
||||
BSHELL_OPCODE_PEXEC,
|
||||
nr_items);
|
||||
return BSHELL_SUCCESS;
|
||||
}
|
||||
|
||||
static const struct compile_value_type cmdcall_type = {
|
||||
.v_load = cmdcall_load,
|
||||
};
|
||||
|
||||
static const struct compile_value_type pipeline_type = {
|
||||
.v_load = pipeline_load,
|
||||
};
|
||||
|
||||
struct compile_result compile_cmdcall(
|
||||
struct compile_ctx *ctx,
|
||||
struct bshell_ast_node *src)
|
||||
{
|
||||
struct bshell_cmdcall_ast_node *cmdcall;
|
||||
cmdcall = (struct bshell_cmdcall_ast_node *)src;
|
||||
size_t nr_args = fx_queue_length(&cmdcall->n_args);
|
||||
for (size_t i = 0; i < nr_args; i++) {
|
||||
struct compile_value *arg = compile_pop_value(ctx);
|
||||
compile_value_load(ctx, arg);
|
||||
compile_value_destroy(arg);
|
||||
}
|
||||
|
||||
bshell_scriptblock_push_instruction(
|
||||
ctx->c_block,
|
||||
BSHELL_OPCODE_LDCMD,
|
||||
nr_args);
|
||||
|
||||
compile_push_value(ctx, &cmdcall_type, src);
|
||||
return COMPILE_OK(0);
|
||||
}
|
||||
|
||||
struct compile_result compile_pipeline(
|
||||
struct compile_ctx *ctx,
|
||||
struct bshell_ast_node *src)
|
||||
{
|
||||
struct bshell_pipeline_ast_node *pipeline;
|
||||
pipeline = (struct bshell_pipeline_ast_node *)src;
|
||||
size_t nr_items = fx_queue_length(&pipeline->n_stages);
|
||||
for (size_t i = 0; i < nr_items; i++) {
|
||||
struct compile_value *item = compile_pop_value(ctx);
|
||||
if (item->v_node->n_type != BSHELL_AST_CMDCALL) {
|
||||
compile_value_load(ctx, item);
|
||||
}
|
||||
compile_value_destroy(item);
|
||||
}
|
||||
|
||||
compile_push_value(ctx, &pipeline_type, src);
|
||||
return COMPILE_OK(0);
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
#ifndef COMPILE_COMPILE_NODE_H_
|
||||
#define COMPILE_COMPILE_NODE_H_
|
||||
|
||||
#include <bshell/ast.h>
|
||||
#include <bshell/parse/token.h>
|
||||
#include <bshell/runtime/operator.h>
|
||||
#include <bshell/runtime/script-block.h>
|
||||
#include <bshell/status.h>
|
||||
#include <fx/queue.h>
|
||||
#include <fx/vector.h>
|
||||
|
||||
#define COMPILE_OK(flags) \
|
||||
((struct compile_result) {.r_status = BSHELL_SUCCESS, \
|
||||
.r_flags = (flags)})
|
||||
#define COMPILE_ERR(status) ((struct compile_result) {.r_status = (status)})
|
||||
|
||||
struct compile_ctx;
|
||||
struct compile_value;
|
||||
|
||||
struct compile_result {
|
||||
enum bshell_status r_status;
|
||||
enum {
|
||||
COMPILE_REPEAT_NODE = 0x00u,
|
||||
} r_flags;
|
||||
};
|
||||
|
||||
typedef struct compile_result (*compile_begin_impl)(struct compile_ctx *);
|
||||
typedef struct compile_result (*compile_end_impl)(struct compile_ctx *);
|
||||
typedef struct compile_result (
|
||||
*compile_node_impl)(struct compile_ctx *, struct bshell_ast_node *);
|
||||
|
||||
enum compile_state_type_id {
|
||||
COMPILE_NORMAL = 0,
|
||||
COMPILE_FSTRING,
|
||||
};
|
||||
|
||||
struct compile_value_type {
|
||||
enum bshell_status (
|
||||
*v_load)(struct compile_ctx *, struct compile_value *);
|
||||
enum bshell_status (
|
||||
*v_store)(struct compile_ctx *, struct compile_value *);
|
||||
};
|
||||
|
||||
struct compile_value {
|
||||
const struct compile_value_type *v_type;
|
||||
enum bshell_operator_id v_op;
|
||||
struct compile_value *v_left, *v_right;
|
||||
struct compile_value **v_args;
|
||||
size_t v_nr_args;
|
||||
struct bshell_ast_node *v_node;
|
||||
unsigned long v_pool;
|
||||
fx_queue_entry v_entry;
|
||||
};
|
||||
|
||||
struct compile_label {
|
||||
size_t l_ip;
|
||||
};
|
||||
|
||||
struct compile_label_ref {
|
||||
fx_queue_entry ref_entry;
|
||||
size_t ref_offset;
|
||||
size_t ref_label_id;
|
||||
};
|
||||
|
||||
struct compile_ctx {
|
||||
fx_queue c_state, c_stack;
|
||||
bshell_scriptblock *c_block;
|
||||
FX_VECTOR_DECLARE(struct compile_label, c_labels);
|
||||
fx_queue c_label_refs;
|
||||
size_t c_depth;
|
||||
};
|
||||
|
||||
struct compile_state_type {
|
||||
size_t s_size;
|
||||
compile_begin_impl s_compile_begin;
|
||||
compile_end_impl s_compile_end;
|
||||
const compile_node_impl *s_compile_node;
|
||||
compile_node_impl s_compile_node_generic;
|
||||
size_t s_nr_compile_node;
|
||||
};
|
||||
|
||||
struct compile_state {
|
||||
const struct compile_state_type *s_type;
|
||||
fx_queue_entry s_entry;
|
||||
size_t s_depth;
|
||||
};
|
||||
|
||||
extern struct compile_state *compile_push_state(
|
||||
struct compile_ctx *ctx,
|
||||
enum compile_state_type_id state_type);
|
||||
extern void compile_pop_state(struct compile_ctx *ctx);
|
||||
extern struct compile_state *compile_get_state(const struct compile_ctx *ctx);
|
||||
|
||||
extern enum bshell_status compile_push_value(
|
||||
struct compile_ctx *ctx,
|
||||
const struct compile_value_type *type,
|
||||
struct bshell_ast_node *node);
|
||||
extern enum bshell_status compile_push_value_array(
|
||||
struct compile_ctx *ctx,
|
||||
const struct compile_value_type *type,
|
||||
struct bshell_ast_node *node,
|
||||
struct compile_value **values,
|
||||
size_t nr_values);
|
||||
extern enum bshell_status compile_push_pool_value(
|
||||
struct compile_ctx *ctx,
|
||||
const struct compile_value_type *type,
|
||||
unsigned long pool_slot);
|
||||
extern enum bshell_status compile_push_op(
|
||||
struct compile_ctx *ctx,
|
||||
struct bshell_ast_node *node,
|
||||
const struct compile_value_type *type,
|
||||
enum bshell_operator_id op,
|
||||
struct compile_value *left,
|
||||
struct compile_value *right);
|
||||
extern struct compile_value *compile_pop_value(struct compile_ctx *ctx);
|
||||
extern void compile_value_load(
|
||||
struct compile_ctx *ctx,
|
||||
struct compile_value *item);
|
||||
extern void compile_value_store(
|
||||
struct compile_ctx *ctx,
|
||||
struct compile_value *item);
|
||||
extern void compile_value_destroy(struct compile_value *item);
|
||||
|
||||
extern size_t compile_declare_label(struct compile_ctx *ctx);
|
||||
extern void compile_define_label(struct compile_ctx *ctx, size_t label_id);
|
||||
extern void compile_ref_label(struct compile_ctx *ctx, size_t label_id);
|
||||
extern enum bshell_status compile_resolve_labels(struct compile_ctx *ctx);
|
||||
|
||||
extern struct compile_result compile_int(
|
||||
struct compile_ctx *ctx,
|
||||
struct bshell_ast_node *src);
|
||||
extern struct compile_result compile_double(
|
||||
struct compile_ctx *ctx,
|
||||
struct bshell_ast_node *src);
|
||||
extern struct compile_result compile_string(
|
||||
struct compile_ctx *ctx,
|
||||
struct bshell_ast_node *src);
|
||||
extern struct compile_result compile_word(
|
||||
struct compile_ctx *ctx,
|
||||
struct bshell_ast_node *src);
|
||||
extern struct compile_result compile_op(
|
||||
struct compile_ctx *ctx,
|
||||
struct bshell_ast_node *src);
|
||||
extern struct compile_result compile_var(
|
||||
struct compile_ctx *ctx,
|
||||
struct bshell_ast_node *src);
|
||||
|
||||
extern struct compile_result compile_fstring(
|
||||
struct compile_ctx *ctx,
|
||||
struct bshell_ast_node *src);
|
||||
extern struct compile_result compile_array(
|
||||
struct compile_ctx *ctx,
|
||||
struct bshell_ast_node *src);
|
||||
extern struct compile_result compile_hashtable_item(
|
||||
struct compile_ctx *ctx,
|
||||
struct bshell_ast_node *src);
|
||||
extern struct compile_result compile_hashtable(
|
||||
struct compile_ctx *ctx,
|
||||
struct bshell_ast_node *src);
|
||||
|
||||
extern struct compile_result compile_block(
|
||||
struct compile_ctx *ctx,
|
||||
struct bshell_ast_node *src);
|
||||
|
||||
extern struct compile_result compile_cmdcall(
|
||||
struct compile_ctx *ctx,
|
||||
struct bshell_ast_node *src);
|
||||
extern struct compile_result compile_pipeline(
|
||||
struct compile_ctx *ctx,
|
||||
struct bshell_ast_node *src);
|
||||
|
||||
extern enum bshell_status compile_if(
|
||||
struct compile_ctx *ctx,
|
||||
struct bshell_ast_node *src);
|
||||
|
||||
extern enum bshell_status compile_block_immediate(
|
||||
struct compile_ctx *ctx,
|
||||
struct bshell_ast_node *src);
|
||||
|
||||
extern enum bshell_status compile_expression(
|
||||
struct compile_ctx *ctx,
|
||||
struct bshell_ast_node *src);
|
||||
extern enum bshell_status compile_node(
|
||||
struct compile_ctx *ctx,
|
||||
struct bshell_ast_node *src);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,40 @@
|
||||
#include "compile-node.h"
|
||||
|
||||
#include <bshell/ast.h>
|
||||
#include <bshell/compile.h>
|
||||
#include <bshell/status.h>
|
||||
|
||||
extern enum bshell_status compile_node(
|
||||
struct compile_ctx *ctx,
|
||||
struct bshell_ast_node *src)
|
||||
{
|
||||
switch (src->n_type) {
|
||||
case BSHELL_AST_IF:
|
||||
return compile_if(ctx, src);
|
||||
case BSHELL_AST_BLOCK:
|
||||
return compile_block_immediate(ctx, src);
|
||||
default:
|
||||
return compile_expression(ctx, src);
|
||||
}
|
||||
|
||||
return BSHELL_SUCCESS;
|
||||
}
|
||||
|
||||
enum bshell_status bshell_compile(
|
||||
struct bshell_ast_node *src,
|
||||
bshell_scriptblock *dest)
|
||||
{
|
||||
struct compile_ctx ctx = {.c_block = dest};
|
||||
|
||||
enum bshell_status status = compile_node(&ctx, src);
|
||||
if (status != BSHELL_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = compile_resolve_labels(&ctx);
|
||||
if (status != BSHELL_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return BSHELL_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
#include "compile-node.h"
|
||||
|
||||
enum bshell_status int_load(
|
||||
struct compile_ctx *ctx,
|
||||
struct compile_value *value)
|
||||
{
|
||||
struct bshell_int_ast_node *i
|
||||
= (struct bshell_int_ast_node *)value->v_node;
|
||||
long long v;
|
||||
fx_value_get_longlong(&i->n_value->tok_number, &v);
|
||||
bshell_scriptblock_push_instruction(ctx->c_block, BSHELL_OPCODE_LDC_INT, v);
|
||||
return BSHELL_SUCCESS;
|
||||
}
|
||||
|
||||
enum bshell_status double_load(
|
||||
struct compile_ctx *ctx,
|
||||
struct compile_value *value)
|
||||
{
|
||||
struct bshell_double_ast_node *d
|
||||
= (struct bshell_double_ast_node *)value->v_node;
|
||||
double v;
|
||||
fx_value_get_double(&d->n_value->tok_number, &v);
|
||||
unsigned long index = bshell_scriptblock_get_double(ctx->c_block, v);
|
||||
bshell_scriptblock_push_instruction(ctx->c_block, BSHELL_OPCODE_LDC_FP, index);
|
||||
return BSHELL_SUCCESS;
|
||||
}
|
||||
|
||||
enum bshell_status string_load(
|
||||
struct compile_ctx *ctx,
|
||||
struct compile_value *value)
|
||||
{
|
||||
struct bshell_string_ast_node *s
|
||||
= (struct bshell_string_ast_node *)value->v_node;
|
||||
unsigned long index = bshell_scriptblock_get_string(
|
||||
ctx->c_block,
|
||||
s->n_value->tok_str);
|
||||
if (index == POOL_INDEX_INVALID) {
|
||||
return BSHELL_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
bshell_scriptblock_push_instruction(
|
||||
ctx->c_block,
|
||||
BSHELL_OPCODE_LDC_STR,
|
||||
index);
|
||||
return BSHELL_SUCCESS;
|
||||
}
|
||||
|
||||
enum bshell_status word_load(
|
||||
struct compile_ctx *ctx,
|
||||
struct compile_value *value)
|
||||
{
|
||||
struct bshell_word_ast_node *s
|
||||
= (struct bshell_word_ast_node *)value->v_node;
|
||||
unsigned long index = bshell_scriptblock_get_string(
|
||||
ctx->c_block,
|
||||
s->n_value->tok_str);
|
||||
if (index == POOL_INDEX_INVALID) {
|
||||
return BSHELL_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
bshell_scriptblock_push_instruction(
|
||||
ctx->c_block,
|
||||
BSHELL_OPCODE_LDC_STR,
|
||||
index);
|
||||
return BSHELL_SUCCESS;
|
||||
}
|
||||
|
||||
static const struct compile_value_type int_type = {
|
||||
.v_load = int_load,
|
||||
};
|
||||
|
||||
static const struct compile_value_type double_type = {
|
||||
.v_load = double_load,
|
||||
};
|
||||
|
||||
static const struct compile_value_type string_type = {
|
||||
.v_load = string_load,
|
||||
};
|
||||
|
||||
static const struct compile_value_type word_type = {
|
||||
.v_load = word_load,
|
||||
};
|
||||
|
||||
struct compile_result compile_int(
|
||||
struct compile_ctx *ctx,
|
||||
struct bshell_ast_node *src)
|
||||
{
|
||||
compile_push_value(ctx, &int_type, src);
|
||||
return COMPILE_OK(0);
|
||||
}
|
||||
|
||||
struct compile_result compile_double(
|
||||
struct compile_ctx *ctx,
|
||||
struct bshell_ast_node *src)
|
||||
{
|
||||
compile_push_value(ctx, &double_type, src);
|
||||
return COMPILE_OK(0);
|
||||
}
|
||||
|
||||
struct compile_result compile_string(
|
||||
struct compile_ctx *ctx,
|
||||
struct bshell_ast_node *src)
|
||||
{
|
||||
compile_push_value(ctx, &string_type, src);
|
||||
return COMPILE_OK(0);
|
||||
}
|
||||
|
||||
struct compile_result compile_word(
|
||||
struct compile_ctx *ctx,
|
||||
struct bshell_ast_node *src)
|
||||
{
|
||||
compile_push_value(ctx, &word_type, src);
|
||||
return COMPILE_OK(0);
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
#include "compile-node.h"
|
||||
|
||||
static struct bshell_ast_iterate_result do_compile_node(
|
||||
struct bshell_ast_node *node,
|
||||
enum bshell_ast_iteration_type it_type,
|
||||
struct bshell_ast_iterator *it,
|
||||
struct compile_ctx *ctx)
|
||||
{
|
||||
if (it_type != BSHELL_AST_ITERATION_POST) {
|
||||
int flags = 0;
|
||||
switch (node->n_type) {
|
||||
case BSHELL_AST_BLOCK:
|
||||
break;
|
||||
default:
|
||||
flags |= BSHELL_AST_ITERATE_ADD_CHILDREN;
|
||||
break;
|
||||
}
|
||||
|
||||
return BSHELL_AST_ITERATE_OK(flags);
|
||||
}
|
||||
|
||||
ctx->c_depth = node->n_it.e_depth;
|
||||
struct compile_state *state = compile_get_state(ctx);
|
||||
while (state->s_depth >= ctx->c_depth && state->s_depth > 0) {
|
||||
compile_pop_state(ctx);
|
||||
state = compile_get_state(ctx);
|
||||
}
|
||||
|
||||
compile_node_impl impl = NULL;
|
||||
|
||||
if (node->n_type < state->s_type->s_nr_compile_node) {
|
||||
impl = state->s_type->s_compile_node[node->n_type];
|
||||
}
|
||||
|
||||
if (!impl) {
|
||||
impl = state->s_type->s_compile_node_generic;
|
||||
}
|
||||
|
||||
if (!impl) {
|
||||
return BSHELL_AST_ITERATE_OK(0);
|
||||
}
|
||||
|
||||
struct compile_result result = impl(ctx, node);
|
||||
unsigned int flags = 0;
|
||||
if (result.r_flags & COMPILE_REPEAT_NODE) {
|
||||
flags |= BSHELL_AST_ITERATE_REPEAT;
|
||||
}
|
||||
|
||||
if (result.r_status == BSHELL_SUCCESS) {
|
||||
return BSHELL_AST_ITERATE_OK(flags);
|
||||
}
|
||||
|
||||
return BSHELL_AST_ITERATE_ERR(result.r_status);
|
||||
}
|
||||
|
||||
enum bshell_status compile_expression(
|
||||
struct compile_ctx *ctx,
|
||||
struct bshell_ast_node *src)
|
||||
{
|
||||
compile_push_state(ctx, COMPILE_NORMAL);
|
||||
|
||||
struct bshell_ast_iterator it = {0};
|
||||
bshell_ast_node_iterate(
|
||||
src,
|
||||
&it,
|
||||
(bshell_ast_iterator_callback)do_compile_node,
|
||||
ctx);
|
||||
|
||||
struct compile_value *result = compile_pop_value(ctx);
|
||||
if (result) {
|
||||
compile_value_load(ctx, result);
|
||||
compile_value_destroy(result);
|
||||
}
|
||||
|
||||
return BSHELL_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
#include "compile-node.h"
|
||||
|
||||
enum bshell_status fstring_load(
|
||||
struct compile_ctx *ctx,
|
||||
struct compile_value *value)
|
||||
{
|
||||
struct bshell_fstring_ast_node *fstring
|
||||
= (struct bshell_fstring_ast_node *)value->v_node;
|
||||
for (size_t i = 0; i < value->v_nr_args; i++) {
|
||||
compile_value_load(ctx, value->v_args[i]);
|
||||
}
|
||||
|
||||
bshell_scriptblock_push_instruction(
|
||||
ctx->c_block,
|
||||
BSHELL_OPCODE_MK_STR,
|
||||
fx_queue_length(&fstring->n_elements));
|
||||
return BSHELL_SUCCESS;
|
||||
}
|
||||
|
||||
static const struct compile_value_type fstring_type = {
|
||||
.v_load = fstring_load,
|
||||
};
|
||||
|
||||
struct compile_result compile_fstring(
|
||||
struct compile_ctx *ctx,
|
||||
struct bshell_ast_node *src)
|
||||
{
|
||||
struct bshell_fstring_ast_node *fstring
|
||||
= (struct bshell_fstring_ast_node *)src;
|
||||
size_t nr_items = fx_queue_length(&fstring->n_elements);
|
||||
struct compile_value **items = calloc(nr_items, sizeof *items);
|
||||
|
||||
for (size_t i = 0; i < nr_items; i++) {
|
||||
struct compile_value *item = compile_pop_value(ctx);
|
||||
items[i] = item;
|
||||
}
|
||||
|
||||
compile_push_value_array(ctx, &fstring_type, src, items, nr_items);
|
||||
return COMPILE_OK(0);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
#include "compile-node.h"
|
||||
|
||||
static const struct compile_value_type hashtable_type = {};
|
||||
static const struct compile_value_type hashtable_item_type = {};
|
||||
|
||||
struct compile_result compile_hashtable(
|
||||
struct compile_ctx *ctx,
|
||||
struct bshell_ast_node *src)
|
||||
{
|
||||
struct bshell_hashtable_ast_node *hashtable
|
||||
= (struct bshell_hashtable_ast_node *)src;
|
||||
size_t nr_items = fx_queue_length(&hashtable->n_items);
|
||||
for (size_t i = 0; i < nr_items; i++) {
|
||||
struct compile_value *item = compile_pop_value(ctx);
|
||||
compile_value_load(ctx, item);
|
||||
compile_value_destroy(item);
|
||||
}
|
||||
|
||||
bshell_scriptblock_push_instruction(
|
||||
ctx->c_block,
|
||||
BSHELL_OPCODE_MK_HTAB,
|
||||
nr_items);
|
||||
compile_push_value(ctx, &hashtable_type, src);
|
||||
return COMPILE_OK(0);
|
||||
}
|
||||
|
||||
struct compile_result compile_hashtable_item(
|
||||
struct compile_ctx *ctx,
|
||||
struct bshell_ast_node *src)
|
||||
{
|
||||
struct compile_value *value = compile_pop_value(ctx);
|
||||
struct compile_value *key = compile_pop_value(ctx);
|
||||
compile_value_load(ctx, key);
|
||||
compile_value_load(ctx, value);
|
||||
compile_value_destroy(key);
|
||||
compile_value_destroy(value);
|
||||
|
||||
compile_push_value(ctx, &hashtable_item_type, src);
|
||||
return COMPILE_OK(0);
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
#include "compile-node.h"
|
||||
|
||||
enum bshell_status compile_if(
|
||||
struct compile_ctx *ctx,
|
||||
struct bshell_ast_node *src)
|
||||
{
|
||||
struct bshell_if_ast_node *if_group;
|
||||
if_group = (struct bshell_if_ast_node *)src;
|
||||
size_t nr_labels = fx_queue_length(&if_group->n_branches);
|
||||
// add one extra label for the end of the if group
|
||||
nr_labels++;
|
||||
|
||||
size_t *label_ids = calloc(nr_labels, sizeof *label_ids);
|
||||
if (!label_ids) {
|
||||
return BSHELL_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
size_t i;
|
||||
for (i = 0; i < nr_labels; i++) {
|
||||
label_ids[i] = compile_declare_label(ctx);
|
||||
}
|
||||
|
||||
i = 0;
|
||||
fx_queue_entry *cur = fx_queue_first(&if_group->n_branches);
|
||||
while (cur) {
|
||||
struct bshell_if_branch_ast_node *branch;
|
||||
branch = fx_unbox(
|
||||
struct bshell_if_branch_ast_node,
|
||||
cur,
|
||||
n_base.n_entry);
|
||||
if (!branch->n_cond) {
|
||||
compile_block_immediate(ctx, branch->n_body);
|
||||
compile_ref_label(ctx, label_ids[nr_labels - 1]);
|
||||
bshell_scriptblock_push_instruction(
|
||||
ctx->c_block,
|
||||
BSHELL_OPCODE_BR,
|
||||
0);
|
||||
break;
|
||||
}
|
||||
|
||||
compile_expression(ctx, branch->n_cond);
|
||||
compile_ref_label(ctx, label_ids[i++]);
|
||||
bshell_scriptblock_push_instruction(
|
||||
ctx->c_block,
|
||||
BSHELL_OPCODE_BR_TRUE,
|
||||
0);
|
||||
|
||||
cur = fx_queue_next(cur);
|
||||
}
|
||||
|
||||
i = 0;
|
||||
cur = fx_queue_first(&if_group->n_branches);
|
||||
while (cur) {
|
||||
struct bshell_if_branch_ast_node *branch = fx_unbox(
|
||||
struct bshell_if_branch_ast_node,
|
||||
cur,
|
||||
n_base.n_entry);
|
||||
if (!branch->n_cond) {
|
||||
break;
|
||||
}
|
||||
|
||||
compile_define_label(ctx, label_ids[i++]);
|
||||
compile_block_immediate(ctx, branch->n_body);
|
||||
cur = fx_queue_next(cur);
|
||||
|
||||
if (i < nr_labels - 2) {
|
||||
compile_ref_label(ctx, label_ids[nr_labels - 1]);
|
||||
bshell_scriptblock_push_instruction(
|
||||
ctx->c_block,
|
||||
BSHELL_OPCODE_BR,
|
||||
0);
|
||||
}
|
||||
}
|
||||
|
||||
compile_define_label(ctx, label_ids[nr_labels - 1]);
|
||||
free(label_ids);
|
||||
|
||||
return BSHELL_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
#include "compile-node.h"
|
||||
|
||||
size_t compile_declare_label(struct compile_ctx *ctx)
|
||||
{
|
||||
size_t id = ctx->c_labels.count;
|
||||
struct compile_label *label = fx_vector_emplace_back(
|
||||
ctx->c_labels,
|
||||
NULL);
|
||||
return id;
|
||||
}
|
||||
|
||||
void compile_define_label(struct compile_ctx *ctx, size_t label_id)
|
||||
{
|
||||
size_t offset = 0;
|
||||
bshell_scriptblock_get_text(ctx->c_block, NULL, &offset);
|
||||
offset *= sizeof(bshell_instruction);
|
||||
ctx->c_labels.items[label_id].l_ip = offset;
|
||||
}
|
||||
|
||||
void compile_ref_label(struct compile_ctx *ctx, size_t label_id)
|
||||
{
|
||||
struct compile_label_ref *ref = malloc(sizeof *ref);
|
||||
if (!ref) {
|
||||
return;
|
||||
}
|
||||
|
||||
memset(ref, 0x0, sizeof *ref);
|
||||
ref->ref_label_id = label_id;
|
||||
bshell_scriptblock_get_text(ctx->c_block, NULL, &ref->ref_offset);
|
||||
ref->ref_offset *= sizeof(bshell_instruction);
|
||||
fx_queue_push_back(&ctx->c_label_refs, &ref->ref_entry);
|
||||
}
|
||||
|
||||
enum bshell_status compile_resolve_labels(struct compile_ctx *ctx)
|
||||
{
|
||||
fx_queue_entry *cur = fx_queue_pop_front(&ctx->c_label_refs);
|
||||
while (cur) {
|
||||
struct compile_label_ref *ref = fx_unbox(
|
||||
struct compile_label_ref,
|
||||
cur,
|
||||
ref_entry);
|
||||
struct compile_label *label = &ctx->c_labels.items
|
||||
[ref->ref_label_id];
|
||||
|
||||
long long rel_value = (long long)label->l_ip
|
||||
- (long long)ref->ref_offset;
|
||||
|
||||
enum bshell_opcode op;
|
||||
uint32_t arg;
|
||||
bshell_scriptblock_read_instruction(
|
||||
ctx->c_block,
|
||||
ref->ref_offset,
|
||||
&op,
|
||||
&arg);
|
||||
arg = (uint32_t)rel_value;
|
||||
bshell_scriptblock_patch_instruction(
|
||||
ctx->c_block,
|
||||
ref->ref_offset,
|
||||
op,
|
||||
arg);
|
||||
|
||||
free(ref);
|
||||
cur = fx_queue_pop_front(&ctx->c_label_refs);
|
||||
}
|
||||
|
||||
return BSHELL_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#include "compile-node.h"
|
||||
|
||||
static const compile_node_impl node_compilers[] = {
|
||||
[BSHELL_AST_INT] = compile_int,
|
||||
[BSHELL_AST_DOUBLE] = compile_double,
|
||||
[BSHELL_AST_STRING] = compile_string,
|
||||
[BSHELL_AST_WORD] = compile_word,
|
||||
[BSHELL_AST_OP] = compile_op,
|
||||
[BSHELL_AST_VAR] = compile_var,
|
||||
[BSHELL_AST_FSTRING] = compile_fstring,
|
||||
[BSHELL_AST_ARRAY] = compile_array,
|
||||
[BSHELL_AST_HASHTABLE] = compile_hashtable,
|
||||
[BSHELL_AST_HASHTABLE_ITEM] = compile_hashtable_item,
|
||||
[BSHELL_AST_CMDCALL] = compile_cmdcall,
|
||||
[BSHELL_AST_PIPELINE] = compile_pipeline,
|
||||
[BSHELL_AST_BLOCK] = compile_block,
|
||||
};
|
||||
static const size_t nr_node_compilers = sizeof node_compilers
|
||||
/ sizeof node_compilers[0];
|
||||
|
||||
const struct compile_state_type normal_state = {
|
||||
.s_size = sizeof(struct compile_state),
|
||||
.s_compile_node = node_compilers,
|
||||
.s_nr_compile_node = nr_node_compilers,
|
||||
};
|
||||
@@ -0,0 +1,126 @@
|
||||
#include "compile-node.h"
|
||||
|
||||
#include <bshell/runtime/operator.h>
|
||||
|
||||
static enum bshell_opcode opcode_for_op(enum bshell_operator_id op)
|
||||
{
|
||||
switch (op) {
|
||||
case BSHELL_OP_ADD:
|
||||
return BSHELL_OPCODE_ADD;
|
||||
case BSHELL_OP_SUBTRACT:
|
||||
return BSHELL_OPCODE_SUB;
|
||||
case BSHELL_OP_MULTIPLY:
|
||||
return BSHELL_OPCODE_MUL;
|
||||
case BSHELL_OP_DIVIDE:
|
||||
return BSHELL_OPCODE_DIV;
|
||||
case BSHELL_OP_MODULO:
|
||||
return BSHELL_OPCODE_MOD;
|
||||
case BSHELL_OP_INCREMENT:
|
||||
return BSHELL_OPCODE_INC;
|
||||
case BSHELL_OP_DECREMENT:
|
||||
return BSHELL_OPCODE_DEC;
|
||||
case BSHELL_OP_LEFT_SHIFT:
|
||||
return BSHELL_OPCODE_SHL;
|
||||
case BSHELL_OP_RIGHT_SHIFT:
|
||||
return BSHELL_OPCODE_SHR;
|
||||
case BSHELL_OP_BINARY_AND:
|
||||
return BSHELL_OPCODE_BAND;
|
||||
case BSHELL_OP_BINARY_OR:
|
||||
return BSHELL_OPCODE_BOR;
|
||||
case BSHELL_OP_BINARY_XOR:
|
||||
return BSHELL_OPCODE_BXOR;
|
||||
case BSHELL_OP_BINARY_NOT:
|
||||
return BSHELL_OPCODE_BNOT;
|
||||
case BSHELL_OP_LESS_THAN:
|
||||
return BSHELL_OPCODE_CMP_LT;
|
||||
case BSHELL_OP_GREATER_THAN:
|
||||
return BSHELL_OPCODE_CMP_GT;
|
||||
case BSHELL_OP_EQUAL:
|
||||
return BSHELL_OPCODE_CMP_EQ;
|
||||
case BSHELL_OP_NOT_EQUAL:
|
||||
return BSHELL_OPCODE_CMP_NE;
|
||||
case BSHELL_OP_LESS_EQUAL:
|
||||
return BSHELL_OPCODE_CMP_LE;
|
||||
case BSHELL_OP_GREATER_EQUAL:
|
||||
return BSHELL_OPCODE_CMP_GE;
|
||||
case BSHELL_OP_LOGICAL_AND:
|
||||
return BSHELL_OPCODE_LAND;
|
||||
case BSHELL_OP_LOGICAL_OR:
|
||||
return BSHELL_OPCODE_LOR;
|
||||
case BSHELL_OP_LOGICAL_XOR:
|
||||
return BSHELL_OPCODE_LXOR;
|
||||
case BSHELL_OP_LOGICAL_NOT:
|
||||
return BSHELL_OPCODE_LNOT;
|
||||
case BSHELL_OP_RANGE:
|
||||
return BSHELL_OPCODE_RANGE;
|
||||
case BSHELL_OP_MATCH:
|
||||
return BSHELL_OPCODE_MATCH;
|
||||
case BSHELL_OP_REPLACE:
|
||||
return BSHELL_OPCODE_REPLACE;
|
||||
case BSHELL_OP_LIKE:
|
||||
return BSHELL_OPCODE_LIKE;
|
||||
case BSHELL_OP_IN:
|
||||
return BSHELL_OPCODE_IN;
|
||||
case BSHELL_OP_FORMAT:
|
||||
return BSHELL_OPCODE_FMT;
|
||||
case BSHELL_OP_CONTAINS:
|
||||
return BSHELL_OPCODE_CONTAINS;
|
||||
case BSHELL_OP_USPLIT:
|
||||
return BSHELL_OPCODE_SPLIT;
|
||||
case BSHELL_OP_BSPLIT:
|
||||
return BSHELL_OPCODE_SPLIT;
|
||||
case BSHELL_OP_UJOIN:
|
||||
return BSHELL_OPCODE_JOIN;
|
||||
case BSHELL_OP_BJOIN:
|
||||
return BSHELL_OPCODE_JOIN;
|
||||
case BSHELL_OP_IS:
|
||||
return BSHELL_OPCODE_IS;
|
||||
case BSHELL_OP_AS:
|
||||
return BSHELL_OPCODE_AS;
|
||||
case BSHELL_OP_ACCESS:
|
||||
return BSHELL_OPCODE_LDPROP;
|
||||
default:
|
||||
return BSHELL_OPCODE_NOP;
|
||||
}
|
||||
}
|
||||
|
||||
enum bshell_status op_load(struct compile_ctx *ctx, struct compile_value *value)
|
||||
{
|
||||
enum bshell_opcode opcode = opcode_for_op(value->v_op);
|
||||
if (opcode != BSHELL_OPCODE_NOP) {
|
||||
compile_value_load(ctx, value->v_right);
|
||||
compile_value_load(ctx, value->v_left);
|
||||
bshell_scriptblock_push_instruction(
|
||||
ctx->c_block,
|
||||
opcode_for_op(value->v_op),
|
||||
0);
|
||||
return BSHELL_SUCCESS;
|
||||
}
|
||||
|
||||
switch (value->v_op) {
|
||||
case BSHELL_OP_ASSIGN:
|
||||
compile_value_load(ctx, value->v_right);
|
||||
compile_value_store(ctx, value->v_left);
|
||||
break;
|
||||
default:
|
||||
return BSHELL_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
return BSHELL_SUCCESS;
|
||||
}
|
||||
|
||||
static const struct compile_value_type op_type = {
|
||||
.v_load = op_load,
|
||||
};
|
||||
|
||||
struct compile_result compile_op(
|
||||
struct compile_ctx *ctx,
|
||||
struct bshell_ast_node *src)
|
||||
{
|
||||
struct bshell_op_ast_node *op = (struct bshell_op_ast_node *)src;
|
||||
struct compile_value *left = NULL, *right = NULL;
|
||||
left = compile_pop_value(ctx);
|
||||
right = compile_pop_value(ctx);
|
||||
compile_push_op(ctx, src, &op_type, op->n_op->op_id, left, right);
|
||||
return COMPILE_OK(0);
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
#include "compile-node.h"
|
||||
|
||||
enum bshell_status compile_push_value(
|
||||
struct compile_ctx *ctx,
|
||||
const struct compile_value_type *type,
|
||||
struct bshell_ast_node *node)
|
||||
{
|
||||
struct compile_value *item = malloc(sizeof *item);
|
||||
if (!item) {
|
||||
return BSHELL_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
memset(item, 0x0, sizeof *item);
|
||||
|
||||
item->v_type = type;
|
||||
item->v_node = node;
|
||||
fx_queue_push_back(&ctx->c_stack, &item->v_entry);
|
||||
|
||||
return BSHELL_SUCCESS;
|
||||
}
|
||||
|
||||
enum bshell_status compile_push_value_array(
|
||||
struct compile_ctx *ctx,
|
||||
const struct compile_value_type *type,
|
||||
struct bshell_ast_node *node,
|
||||
struct compile_value **values,
|
||||
size_t nr_values)
|
||||
{
|
||||
struct compile_value *item = malloc(sizeof *item);
|
||||
if (!item) {
|
||||
return BSHELL_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
memset(item, 0x0, sizeof *item);
|
||||
|
||||
item->v_type = type;
|
||||
item->v_node = node;
|
||||
item->v_args = values;
|
||||
item->v_nr_args = nr_values;
|
||||
fx_queue_push_back(&ctx->c_stack, &item->v_entry);
|
||||
|
||||
return BSHELL_SUCCESS;
|
||||
}
|
||||
|
||||
enum bshell_status compile_push_pool_value(
|
||||
struct compile_ctx *ctx,
|
||||
const struct compile_value_type *type,
|
||||
unsigned long pool_slot)
|
||||
{
|
||||
struct compile_value *item = malloc(sizeof *item);
|
||||
if (!item) {
|
||||
return BSHELL_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
memset(item, 0x0, sizeof *item);
|
||||
|
||||
item->v_type = type;
|
||||
item->v_pool = pool_slot;
|
||||
fx_queue_push_back(&ctx->c_stack, &item->v_entry);
|
||||
|
||||
return BSHELL_SUCCESS;
|
||||
}
|
||||
|
||||
enum bshell_status compile_push_op(
|
||||
struct compile_ctx *ctx,
|
||||
struct bshell_ast_node *node,
|
||||
const struct compile_value_type *type,
|
||||
enum bshell_operator_id op,
|
||||
struct compile_value *left,
|
||||
struct compile_value *right)
|
||||
{
|
||||
struct compile_value *item = malloc(sizeof *item);
|
||||
if (!item) {
|
||||
return BSHELL_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
memset(item, 0x0, sizeof *item);
|
||||
|
||||
item->v_type = type;
|
||||
item->v_node = node;
|
||||
item->v_op = op;
|
||||
item->v_left = left;
|
||||
item->v_right = right;
|
||||
fx_queue_push_back(&ctx->c_stack, &item->v_entry);
|
||||
|
||||
return BSHELL_SUCCESS;
|
||||
}
|
||||
|
||||
struct compile_value *compile_pop_value(struct compile_ctx *ctx)
|
||||
{
|
||||
fx_queue_entry *entry = fx_queue_pop_back(&ctx->c_stack);
|
||||
if (!entry) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return fx_unbox(struct compile_value, entry, v_entry);
|
||||
}
|
||||
|
||||
void compile_value_load(struct compile_ctx *ctx, struct compile_value *item)
|
||||
{
|
||||
if (item->v_type->v_load) {
|
||||
item->v_type->v_load(ctx, item);
|
||||
}
|
||||
}
|
||||
|
||||
void compile_value_store(struct compile_ctx *ctx, struct compile_value *item)
|
||||
{
|
||||
if (item->v_type->v_store) {
|
||||
item->v_type->v_store(ctx, item);
|
||||
}
|
||||
}
|
||||
|
||||
void compile_value_destroy(struct compile_value *value)
|
||||
{
|
||||
if (value->v_left) {
|
||||
compile_value_destroy(value->v_left);
|
||||
}
|
||||
|
||||
if (value->v_right) {
|
||||
compile_value_destroy(value->v_right);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < value->v_nr_args; i++) {
|
||||
compile_value_destroy(value->v_args[i]);
|
||||
}
|
||||
|
||||
if (value->v_args) {
|
||||
free(value->v_args);
|
||||
}
|
||||
|
||||
free(value);
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
#include "compile-node.h"
|
||||
|
||||
extern const struct compile_state_type normal_state;
|
||||
static const struct compile_state_type *state_types[] = {
|
||||
[COMPILE_NORMAL] = &normal_state,
|
||||
};
|
||||
static const size_t nr_state_types = sizeof state_types / sizeof state_types[0];
|
||||
|
||||
struct compile_state *compile_push_state(
|
||||
struct compile_ctx *ctx,
|
||||
enum compile_state_type_id state_type_id)
|
||||
{
|
||||
if (state_type_id >= nr_state_types) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct compile_state_type *state_type = state_types
|
||||
[state_type_id];
|
||||
if (!state_type) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct compile_state *state = malloc(state_type->s_size);
|
||||
if (!state) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
state->s_type = state_type;
|
||||
state->s_depth = ctx->c_depth;
|
||||
fx_queue_push_back(&ctx->c_state, &state->s_entry);
|
||||
|
||||
if (state_type->s_compile_begin) {
|
||||
state_type->s_compile_begin(ctx);
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
void compile_pop_state(struct compile_ctx *ctx)
|
||||
{
|
||||
struct compile_state *state = compile_get_state(ctx);
|
||||
if (!state) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fx_queue_prev(&state->s_entry)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (state->s_type->s_compile_end) {
|
||||
state->s_type->s_compile_end(ctx);
|
||||
}
|
||||
|
||||
fx_queue_pop_back(&ctx->c_state);
|
||||
free(state);
|
||||
}
|
||||
|
||||
struct compile_state *compile_get_state(const struct compile_ctx *ctx)
|
||||
{
|
||||
fx_queue_entry *entry = fx_queue_last(&ctx->c_state);
|
||||
if (!entry) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return fx_unbox(struct compile_state, entry, s_entry);
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
#include "compile-node.h"
|
||||
|
||||
enum bshell_status var_load(
|
||||
struct compile_ctx *ctx,
|
||||
struct compile_value *value)
|
||||
{
|
||||
struct bshell_var_ast_node *var
|
||||
= (struct bshell_var_ast_node *)value->v_node;
|
||||
unsigned long index = bshell_scriptblock_get_string(
|
||||
ctx->c_block,
|
||||
var->n_ident->tok_str);
|
||||
if (index == POOL_INDEX_INVALID) {
|
||||
return BSHELL_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
bshell_scriptblock_push_instruction(
|
||||
ctx->c_block,
|
||||
BSHELL_OPCODE_LDLOCAL,
|
||||
index);
|
||||
return BSHELL_SUCCESS;
|
||||
}
|
||||
|
||||
enum bshell_status var_store(
|
||||
struct compile_ctx *ctx,
|
||||
struct compile_value *value)
|
||||
{
|
||||
struct bshell_var_ast_node *var
|
||||
= (struct bshell_var_ast_node *)value->v_node;
|
||||
unsigned long index = bshell_scriptblock_get_string(
|
||||
ctx->c_block,
|
||||
var->n_ident->tok_str);
|
||||
if (index == POOL_INDEX_INVALID) {
|
||||
return BSHELL_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
bshell_scriptblock_push_instruction(
|
||||
ctx->c_block,
|
||||
BSHELL_OPCODE_STLOCAL,
|
||||
index);
|
||||
return BSHELL_SUCCESS;
|
||||
}
|
||||
|
||||
static const struct compile_value_type var_type = {
|
||||
.v_load = var_load,
|
||||
.v_store = var_store,
|
||||
};
|
||||
|
||||
struct compile_result compile_var(
|
||||
struct compile_ctx *ctx,
|
||||
struct bshell_ast_node *src)
|
||||
{
|
||||
compile_push_value(ctx, &var_type, src);
|
||||
return COMPILE_OK(0);
|
||||
}
|
||||
Reference in New Issue
Block a user