bshell: implement bytecode generation for arithmetic expressions and if-statements
This commit is contained in:
@@ -0,0 +1,12 @@
|
|||||||
|
#ifndef COMPILE_H_
|
||||||
|
#define COMPILE_H_
|
||||||
|
|
||||||
|
#include "script-block.h"
|
||||||
|
|
||||||
|
struct ast_node;
|
||||||
|
|
||||||
|
extern enum bshell_status bshell_compile(
|
||||||
|
struct ast_node *src,
|
||||||
|
bshell_scriptblock *dest);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
#include "compile-node.h"
|
||||||
|
|
||||||
|
struct compile_result compile_array(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src)
|
||||||
|
{
|
||||||
|
struct array_ast_node *array = (struct array_ast_node *)src;
|
||||||
|
bshell_scriptblock_push_instruction(
|
||||||
|
ctx->c_block,
|
||||||
|
OPCODE_MK_ARRAY,
|
||||||
|
fx_queue_length(&array->n_items));
|
||||||
|
return COMPILE_OK(0);
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
#include "../compile.h"
|
||||||
|
#include "compile-node.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,
|
||||||
|
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 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 ast_node *src)
|
||||||
|
{
|
||||||
|
enum bshell_status status = BSHELL_SUCCESS;
|
||||||
|
struct block_ast_node *block = (struct block_ast_node *)src;
|
||||||
|
|
||||||
|
fx_queue_entry *cur = fx_queue_first(&block->n_statements);
|
||||||
|
while (cur && status == BSHELL_SUCCESS) {
|
||||||
|
struct ast_node *node = fx_unbox(struct ast_node, cur, n_entry);
|
||||||
|
status = compile_node(ctx, node);
|
||||||
|
cur = fx_queue_next(cur);
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
#include "compile-node.h"
|
||||||
|
|
||||||
|
enum bshell_status cmdcall_load(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct compile_value *value)
|
||||||
|
{
|
||||||
|
struct cmdcall_ast_node *cmdcall = (struct cmdcall_ast_node *)
|
||||||
|
value->v_node;
|
||||||
|
bshell_scriptblock_push_instruction(ctx->c_block, OPCODE_PEXEC, 1);
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status pipeline_load(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct compile_value *value)
|
||||||
|
{
|
||||||
|
struct pipeline_ast_node *pipeline = (struct pipeline_ast_node *)
|
||||||
|
value->v_node;
|
||||||
|
size_t nr_items = fx_queue_length(&pipeline->n_stages);
|
||||||
|
bshell_scriptblock_push_instruction(
|
||||||
|
ctx->c_block,
|
||||||
|
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 ast_node *src)
|
||||||
|
{
|
||||||
|
struct cmdcall_ast_node *cmdcall = (struct 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,
|
||||||
|
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 ast_node *src)
|
||||||
|
{
|
||||||
|
struct pipeline_ast_node *pipeline = (struct 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 != 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,175 @@
|
|||||||
|
#ifndef COMPILE_COMPILE_NODE_H_
|
||||||
|
#define COMPILE_COMPILE_NODE_H_
|
||||||
|
|
||||||
|
#include "../ast/ast.h"
|
||||||
|
#include "../operator.h"
|
||||||
|
#include "../parse/token.h"
|
||||||
|
#include "../script-block.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 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 operator_id v_op;
|
||||||
|
struct compile_value *v_left, *v_right;
|
||||||
|
struct 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 ast_node *node);
|
||||||
|
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,
|
||||||
|
const struct compile_value_type *type,
|
||||||
|
enum 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 ast_node *src);
|
||||||
|
extern struct compile_result compile_string(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src);
|
||||||
|
extern struct compile_result compile_word(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src);
|
||||||
|
extern struct compile_result compile_op(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src);
|
||||||
|
extern struct compile_result compile_var(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src);
|
||||||
|
|
||||||
|
extern struct compile_result compile_fstring(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src);
|
||||||
|
extern struct compile_result compile_array(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src);
|
||||||
|
extern struct compile_result compile_hashtable_item(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src);
|
||||||
|
extern struct compile_result compile_hashtable(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src);
|
||||||
|
|
||||||
|
extern struct compile_result compile_block(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src);
|
||||||
|
|
||||||
|
extern struct compile_result compile_cmdcall(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src);
|
||||||
|
extern struct compile_result compile_pipeline(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src);
|
||||||
|
|
||||||
|
extern enum bshell_status compile_if(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src);
|
||||||
|
|
||||||
|
extern enum bshell_status compile_block_immediate(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src);
|
||||||
|
|
||||||
|
extern enum bshell_status compile_expression(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src);
|
||||||
|
extern enum bshell_status compile_node(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
#include "../compile.h"
|
||||||
|
|
||||||
|
#include "../ast/ast.h"
|
||||||
|
#include "../debug.h"
|
||||||
|
#include "../status.h"
|
||||||
|
#include "compile-node.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
extern enum bshell_status compile_node(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src)
|
||||||
|
{
|
||||||
|
switch (src->n_type) {
|
||||||
|
case AST_IF:
|
||||||
|
return compile_if(ctx, src);
|
||||||
|
case AST_BLOCK:
|
||||||
|
return compile_block_immediate(ctx, src);
|
||||||
|
default:
|
||||||
|
return compile_expression(ctx, src);
|
||||||
|
}
|
||||||
|
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status bshell_compile(
|
||||||
|
struct 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,85 @@
|
|||||||
|
#include "compile-node.h"
|
||||||
|
|
||||||
|
enum bshell_status int_load(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct compile_value *value)
|
||||||
|
{
|
||||||
|
struct int_ast_node *i = (struct int_ast_node *)value->v_node;
|
||||||
|
bshell_scriptblock_push_instruction(
|
||||||
|
ctx->c_block,
|
||||||
|
OPCODE_LDC_INT,
|
||||||
|
i->n_value->tok_int);
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status string_load(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct compile_value *value)
|
||||||
|
{
|
||||||
|
struct string_ast_node *s = (struct 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,
|
||||||
|
OPCODE_LDC_STR,
|
||||||
|
index);
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status word_load(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct compile_value *value)
|
||||||
|
{
|
||||||
|
struct word_ast_node *s = (struct 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,
|
||||||
|
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 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 ast_node *src)
|
||||||
|
{
|
||||||
|
compile_push_value(ctx, &int_type, src);
|
||||||
|
return COMPILE_OK(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct compile_result compile_string(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src)
|
||||||
|
{
|
||||||
|
compile_push_value(ctx, &string_type, src);
|
||||||
|
return COMPILE_OK(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct compile_result compile_word(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src)
|
||||||
|
{
|
||||||
|
compile_push_value(ctx, &word_type, src);
|
||||||
|
return COMPILE_OK(0);
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
#include "compile-node.h"
|
||||||
|
|
||||||
|
static struct ast_iterate_result do_compile_node(
|
||||||
|
struct ast_node *node,
|
||||||
|
enum ast_iteration_type it_type,
|
||||||
|
struct ast_iterator *it,
|
||||||
|
struct compile_ctx *ctx)
|
||||||
|
{
|
||||||
|
if (it_type != AST_ITERATION_POST) {
|
||||||
|
int flags = 0;
|
||||||
|
switch (node->n_type) {
|
||||||
|
case AST_BLOCK:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
flags |= AST_ITERATE_ADD_CHILDREN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 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 AST_ITERATE_OK(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct compile_result result = impl(ctx, node);
|
||||||
|
unsigned int flags = 0;
|
||||||
|
if (result.r_flags & COMPILE_REPEAT_NODE) {
|
||||||
|
flags |= AST_ITERATE_REPEAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.r_status == BSHELL_SUCCESS) {
|
||||||
|
return AST_ITERATE_OK(flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
return AST_ITERATE_ERR(result.r_status);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status compile_expression(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src)
|
||||||
|
{
|
||||||
|
compile_push_state(ctx, COMPILE_NORMAL);
|
||||||
|
|
||||||
|
struct ast_iterator it = {0};
|
||||||
|
ast_node_iterate(src, &it, (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,35 @@
|
|||||||
|
#include "compile-node.h"
|
||||||
|
|
||||||
|
enum bshell_status fstring_load(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct compile_value *value)
|
||||||
|
{
|
||||||
|
struct fstring_ast_node *fstring = (struct fstring_ast_node *)
|
||||||
|
value->v_node;
|
||||||
|
|
||||||
|
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 ast_node *src)
|
||||||
|
{
|
||||||
|
struct fstring_ast_node *fstring = (struct fstring_ast_node *)src;
|
||||||
|
size_t nr_items = fx_queue_length(&fstring->n_elements);
|
||||||
|
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,
|
||||||
|
OPCODE_MK_STR,
|
||||||
|
fx_queue_length(&fstring->n_elements));
|
||||||
|
|
||||||
|
compile_push_value(ctx, &fstring_type, src);
|
||||||
|
return COMPILE_OK(0);
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
#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 ast_node *src)
|
||||||
|
{
|
||||||
|
struct hashtable_ast_node *hashtable = (struct 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,
|
||||||
|
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 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,75 @@
|
|||||||
|
#include "compile-node.h"
|
||||||
|
|
||||||
|
enum bshell_status compile_if(struct compile_ctx *ctx, struct ast_node *src)
|
||||||
|
{
|
||||||
|
struct if_ast_node *if_group = (struct 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 if_branch_ast_node *branch = fx_unbox(
|
||||||
|
struct 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,
|
||||||
|
OPCODE_BR,
|
||||||
|
0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
compile_expression(ctx, branch->n_cond);
|
||||||
|
compile_ref_label(ctx, label_ids[i++]);
|
||||||
|
bshell_scriptblock_push_instruction(
|
||||||
|
ctx->c_block,
|
||||||
|
OPCODE_BR_TRUE,
|
||||||
|
0);
|
||||||
|
|
||||||
|
cur = fx_queue_next(cur);
|
||||||
|
}
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
cur = fx_queue_first(&if_group->n_branches);
|
||||||
|
while (cur) {
|
||||||
|
struct if_branch_ast_node *branch = fx_unbox(
|
||||||
|
struct 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,
|
||||||
|
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,24 @@
|
|||||||
|
#include "compile-node.h"
|
||||||
|
|
||||||
|
static const compile_node_impl node_compilers[] = {
|
||||||
|
[AST_INT] = compile_int,
|
||||||
|
[AST_STRING] = compile_string,
|
||||||
|
[AST_WORD] = compile_word,
|
||||||
|
[AST_OP] = compile_op,
|
||||||
|
[AST_VAR] = compile_var,
|
||||||
|
[AST_FSTRING] = compile_fstring,
|
||||||
|
[AST_ARRAY] = compile_array,
|
||||||
|
[AST_HASHTABLE] = compile_hashtable,
|
||||||
|
[AST_HASHTABLE_ITEM] = compile_hashtable_item,
|
||||||
|
[AST_CMDCALL] = compile_cmdcall,
|
||||||
|
[AST_PIPELINE] = compile_pipeline,
|
||||||
|
[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,121 @@
|
|||||||
|
#include "../operator.h"
|
||||||
|
#include "compile-node.h"
|
||||||
|
|
||||||
|
static enum bshell_opcode opcode_for_op(enum operator_id op)
|
||||||
|
{
|
||||||
|
switch (op) {
|
||||||
|
case OP_ADD:
|
||||||
|
return OPCODE_ADD;
|
||||||
|
case OP_SUBTRACT:
|
||||||
|
return OPCODE_SUB;
|
||||||
|
case OP_MULTIPLY:
|
||||||
|
return OPCODE_MUL;
|
||||||
|
case OP_DIVIDE:
|
||||||
|
return OPCODE_DIV;
|
||||||
|
case OP_MODULO:
|
||||||
|
return OPCODE_MOD;
|
||||||
|
case OP_INCREMENT:
|
||||||
|
return OPCODE_INC;
|
||||||
|
case OP_DECREMENT:
|
||||||
|
return OPCODE_DEC;
|
||||||
|
case OP_LEFT_SHIFT:
|
||||||
|
return OPCODE_SHL;
|
||||||
|
case OP_RIGHT_SHIFT:
|
||||||
|
return OPCODE_SHR;
|
||||||
|
case OP_BINARY_AND:
|
||||||
|
return OPCODE_BAND;
|
||||||
|
case OP_BINARY_OR:
|
||||||
|
return OPCODE_BOR;
|
||||||
|
case OP_BINARY_XOR:
|
||||||
|
return OPCODE_BXOR;
|
||||||
|
case OP_BINARY_NOT:
|
||||||
|
return OPCODE_BNOT;
|
||||||
|
case OP_LESS_THAN:
|
||||||
|
return OPCODE_CMP_LT;
|
||||||
|
case OP_GREATER_THAN:
|
||||||
|
return OPCODE_CMP_GT;
|
||||||
|
case OP_EQUAL:
|
||||||
|
return OPCODE_CMP_EQ;
|
||||||
|
case OP_NOT_EQUAL:
|
||||||
|
return OPCODE_CMP_NE;
|
||||||
|
case OP_LESS_EQUAL:
|
||||||
|
return OPCODE_CMP_LE;
|
||||||
|
case OP_GREATER_EQUAL:
|
||||||
|
return OPCODE_CMP_GE;
|
||||||
|
case OP_LOGICAL_AND:
|
||||||
|
return OPCODE_LAND;
|
||||||
|
case OP_LOGICAL_OR:
|
||||||
|
return OPCODE_LOR;
|
||||||
|
case OP_LOGICAL_XOR:
|
||||||
|
return OPCODE_LXOR;
|
||||||
|
case OP_LOGICAL_NOT:
|
||||||
|
return OPCODE_LNOT;
|
||||||
|
case OP_RANGE:
|
||||||
|
return OPCODE_RANGE;
|
||||||
|
case OP_MATCH:
|
||||||
|
return OPCODE_MATCH;
|
||||||
|
case OP_REPLACE:
|
||||||
|
return OPCODE_REPLACE;
|
||||||
|
case OP_LIKE:
|
||||||
|
return OPCODE_LIKE;
|
||||||
|
case OP_IN:
|
||||||
|
return OPCODE_IN;
|
||||||
|
case OP_FORMAT:
|
||||||
|
return OPCODE_FMT;
|
||||||
|
case OP_CONTAINS:
|
||||||
|
return OPCODE_CONTAINS;
|
||||||
|
case OP_USPLIT:
|
||||||
|
return OPCODE_SPLIT;
|
||||||
|
case OP_BSPLIT:
|
||||||
|
return OPCODE_SPLIT;
|
||||||
|
case OP_UJOIN:
|
||||||
|
return OPCODE_JOIN;
|
||||||
|
case OP_BJOIN:
|
||||||
|
return OPCODE_JOIN;
|
||||||
|
case OP_IS:
|
||||||
|
return OPCODE_IS;
|
||||||
|
case OP_AS:
|
||||||
|
return OPCODE_AS;
|
||||||
|
default:
|
||||||
|
return 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 != 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 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 ast_node *src)
|
||||||
|
{
|
||||||
|
struct op_ast_node *op = (struct op_ast_node *)src;
|
||||||
|
struct compile_value *left = NULL, *right = NULL;
|
||||||
|
right = compile_pop_value(ctx);
|
||||||
|
left = compile_pop_value(ctx);
|
||||||
|
compile_push_op(ctx, &op_type, op->n_op->op_id, left, right);
|
||||||
|
return COMPILE_OK(0);
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
#include "compile-node.h"
|
||||||
|
|
||||||
|
enum bshell_status compile_push_value(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
const struct compile_value_type *type,
|
||||||
|
struct 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_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,
|
||||||
|
const struct compile_value_type *type,
|
||||||
|
enum 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_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)
|
||||||
|
{
|
||||||
|
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,50 @@
|
|||||||
|
#include "compile-node.h"
|
||||||
|
|
||||||
|
enum bshell_status var_load(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct compile_value *value)
|
||||||
|
{
|
||||||
|
struct var_ast_node *var = (struct 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,
|
||||||
|
OPCODE_LDLOCAL,
|
||||||
|
index);
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status var_store(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct compile_value *value)
|
||||||
|
{
|
||||||
|
struct var_ast_node *var = (struct 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,
|
||||||
|
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 ast_node *src)
|
||||||
|
{
|
||||||
|
compile_push_value(ctx, &var_type, src);
|
||||||
|
return COMPILE_OK(0);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user