cleaned up bytecode generation code
This commit is contained in:
+100
-99
@@ -51,7 +51,6 @@
|
|||||||
#include "compile.h"
|
#include "compile.h"
|
||||||
#include "ASTi.h"
|
#include "ASTi.h"
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Error *error;
|
Error *error;
|
||||||
BPAlloc *alloc;
|
BPAlloc *alloc;
|
||||||
@@ -60,6 +59,26 @@ typedef struct {
|
|||||||
jmp_buf env;
|
jmp_buf env;
|
||||||
} CodegenContext;
|
} CodegenContext;
|
||||||
|
|
||||||
|
typedef Promise Label;
|
||||||
|
|
||||||
|
static void setLabel(Label *label, long long int value)
|
||||||
|
{
|
||||||
|
Promise *promise = (Promise*) label;
|
||||||
|
Promise_Resolve(promise, &value, sizeof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setLabelHere(Label *label, CodegenContext *ctx)
|
||||||
|
{
|
||||||
|
long long int value = ExeBuilder_InstrCount(ctx->builder);
|
||||||
|
setLabel(label, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void freeLabel(Label *label)
|
||||||
|
{
|
||||||
|
Promise *promise = (Promise*) label;
|
||||||
|
Promise_Free(promise);
|
||||||
|
}
|
||||||
|
|
||||||
static void okNowJump(CodegenContext *ctx)
|
static void okNowJump(CodegenContext *ctx)
|
||||||
{
|
{
|
||||||
longjmp(ctx->env, 1);
|
longjmp(ctx->env, 1);
|
||||||
@@ -147,7 +166,47 @@ static void emitInstr_ASS(CodegenContext *ctx, const char *name, int off, int le
|
|||||||
emitInstr(ctx, OPCODE_ASS, opv, 1, off, len);
|
emitInstr(ctx, OPCODE_ASS, opv, 1, off, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Promise *newOffsetPromise(CodegenContext *ctx)
|
static void emitInstr_RETURN(CodegenContext *ctx,
|
||||||
|
long long int op0,
|
||||||
|
int off, int len)
|
||||||
|
{
|
||||||
|
Operand opv[1] = {
|
||||||
|
{ .type = OPTP_INT, .as_int = op0 }
|
||||||
|
};
|
||||||
|
emitInstr(ctx, OPCODE_RETURN, opv, 1, off, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void emitInstr_JUMP(CodegenContext *ctx,
|
||||||
|
Promise *op0,
|
||||||
|
int off, int len)
|
||||||
|
{
|
||||||
|
Operand opv[1] = {
|
||||||
|
{ .type = OPTP_PROMISE, .as_promise = op0 }
|
||||||
|
};
|
||||||
|
emitInstr(ctx, OPCODE_JUMP, opv, 1, off, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void emitInstr_JUMPIFNOTANDPOP(CodegenContext *ctx,
|
||||||
|
Promise *op0,
|
||||||
|
int off, int len)
|
||||||
|
{
|
||||||
|
Operand opv[1] = {
|
||||||
|
{ .type = OPTP_PROMISE, .as_promise = op0 }
|
||||||
|
};
|
||||||
|
emitInstr(ctx, OPCODE_JUMPIFNOTANDPOP, opv, 1, off, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void emitInstr_JUMPIFANDPOP(CodegenContext *ctx,
|
||||||
|
long long int op0,
|
||||||
|
int off, int len)
|
||||||
|
{
|
||||||
|
Operand opv[1] = {
|
||||||
|
{ .type = OPTP_INT, .as_int = op0 }
|
||||||
|
};
|
||||||
|
emitInstr(ctx, OPCODE_JUMPIFANDPOP, opv, 1, off, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Label *newLabel(CodegenContext *ctx)
|
||||||
{
|
{
|
||||||
Promise *promise = Promise_New(ctx->alloc, sizeof(long long int));
|
Promise *promise = Promise_New(ctx->alloc, sizeof(long long int));
|
||||||
if(promise != NULL)
|
if(promise != NULL)
|
||||||
@@ -208,8 +267,8 @@ static void emitInstrForFuncCallNode(CodegenContext *ctx, CallExprNode *expr,
|
|||||||
|
|
||||||
static void emitInstrForFuncNode(CodegenContext *ctx, FunctionNode *func, Promise *break_dest)
|
static void emitInstrForFuncNode(CodegenContext *ctx, FunctionNode *func, Promise *break_dest)
|
||||||
{
|
{
|
||||||
Promise *func_index = newOffsetPromise(ctx);
|
Label *func_index = newLabel(ctx);
|
||||||
Promise *jump_index = newOffsetPromise(ctx);
|
Label *jump_index = newLabel(ctx);
|
||||||
|
|
||||||
// Push function.
|
// Push function.
|
||||||
{
|
{
|
||||||
@@ -219,17 +278,10 @@ static void emitInstrForFuncNode(CodegenContext *ctx, FunctionNode *func, Promis
|
|||||||
};
|
};
|
||||||
emitInstr(ctx, OPCODE_PUSHFUN, ops, 2, func->base.offset, func->base.length);
|
emitInstr(ctx, OPCODE_PUSHFUN, ops, 2, func->base.offset, func->base.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
emitInstr_ASS(ctx, func->name, func->base.offset, func->base.length); // Assign variable
|
emitInstr_ASS(ctx, func->name, func->base.offset, func->base.length); // Assign variable
|
||||||
emitInstr_POP1(ctx, func->base.offset, func->base.length); // Pop function object
|
emitInstr_POP1(ctx, func->base.offset, func->base.length); // Pop function object
|
||||||
|
emitInstr_JUMP(ctx, jump_index, func->base.offset, func->base.length); // Jump after the function code
|
||||||
// Jump after the function code.
|
setLabelHere(func_index, ctx); // This is the function code index.
|
||||||
Operand op = { .type = OPTP_PROMISE, .as_promise = jump_index };
|
|
||||||
emitInstr(ctx, OPCODE_JUMP, &op, 1, func->base.offset, func->base.length);
|
|
||||||
|
|
||||||
// This is the function code index.
|
|
||||||
long long int temp = ExeBuilder_InstrCount(ctx->builder);
|
|
||||||
Promise_Resolve(func_index, &temp, sizeof(temp));
|
|
||||||
|
|
||||||
// Compile the function body.
|
// Compile the function body.
|
||||||
{
|
{
|
||||||
@@ -249,68 +301,45 @@ static void emitInstrForFuncNode(CodegenContext *ctx, FunctionNode *func, Promis
|
|||||||
|
|
||||||
// Write a return instruction, just
|
// Write a return instruction, just
|
||||||
// in case it didn't already return.
|
// in case it didn't already return.
|
||||||
Operand op = (Operand) { .type = OPTP_INT, .as_int = 0 };
|
emitInstr_RETURN(ctx, 0, func->body->offset, 0);
|
||||||
emitInstr(ctx, OPCODE_RETURN, &op, 1, func->body->offset, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is the first index after the function code.
|
// This is the first index after the function code.
|
||||||
temp = ExeBuilder_InstrCount(ctx->builder);
|
setLabelHere(jump_index, ctx);
|
||||||
Promise_Resolve(jump_index, &temp, sizeof(temp));
|
|
||||||
|
|
||||||
Promise_Free(func_index);
|
freeLabel(func_index);
|
||||||
Promise_Free(jump_index);
|
freeLabel(jump_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void emitInstrForIfElseNode(CodegenContext *ctx, IfElseNode *ifelse, Promise *break_dest)
|
static void emitInstrForIfElseNode(CodegenContext *ctx, IfElseNode *ifelse, Promise *break_dest)
|
||||||
{
|
{
|
||||||
emitInstrForNode(ctx, ifelse->condition, break_dest);
|
emitInstrForNode(ctx, ifelse->condition, break_dest);
|
||||||
|
|
||||||
if(ifelse->false_branch)
|
if(ifelse->false_branch)
|
||||||
{
|
{
|
||||||
Promise *else_offset = newOffsetPromise(ctx);
|
Label *else_offset = newLabel(ctx);
|
||||||
Promise *done_offset = newOffsetPromise(ctx);
|
Label *done_offset = newLabel(ctx);
|
||||||
|
emitInstr_JUMPIFNOTANDPOP(ctx, else_offset, ifelse->base.offset, ifelse->base.length);
|
||||||
Operand op = { .type = OPTP_PROMISE, .as_promise = else_offset };
|
|
||||||
emitInstr(ctx, OPCODE_JUMPIFNOTANDPOP, &op, 1, ifelse->base.offset, ifelse->base.length);
|
|
||||||
|
|
||||||
emitInstrForNode(ctx, ifelse->true_branch, break_dest);
|
emitInstrForNode(ctx, ifelse->true_branch, break_dest);
|
||||||
|
|
||||||
if(ifelse->true_branch->kind == NODE_EXPR)
|
if(ifelse->true_branch->kind == NODE_EXPR)
|
||||||
emitInstr_POP(ctx, 1, ifelse->true_branch->offset, 0);
|
emitInstr_POP(ctx, 1, ifelse->true_branch->offset, 0);
|
||||||
|
emitInstr_JUMP(ctx, done_offset, ifelse->base.offset, ifelse->base.length);
|
||||||
op = (Operand) { .type = OPTP_PROMISE, .as_promise = done_offset };
|
setLabelHere(else_offset, ctx);
|
||||||
emitInstr(ctx, OPCODE_JUMP, &op, 1, ifelse->base.offset, ifelse->base.length);
|
|
||||||
|
|
||||||
long long int temp = ExeBuilder_InstrCount(ctx->builder);
|
|
||||||
Promise_Resolve(else_offset, &temp, sizeof(temp));
|
|
||||||
|
|
||||||
emitInstrForNode(ctx, ifelse->false_branch, break_dest);
|
emitInstrForNode(ctx, ifelse->false_branch, break_dest);
|
||||||
|
|
||||||
if(ifelse->false_branch->kind == NODE_EXPR)
|
if(ifelse->false_branch->kind == NODE_EXPR)
|
||||||
emitInstr_POP1(ctx, ifelse->false_branch->offset, 0);
|
emitInstr_POP1(ctx, ifelse->false_branch->offset, 0);
|
||||||
|
setLabelHere(done_offset, ctx);
|
||||||
temp = ExeBuilder_InstrCount(ctx->builder);
|
freeLabel(else_offset);
|
||||||
Promise_Resolve(done_offset, &temp, sizeof(temp));
|
freeLabel(done_offset);
|
||||||
|
|
||||||
Promise_Free(else_offset);
|
|
||||||
Promise_Free(done_offset);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Promise *done_offset = newOffsetPromise(ctx);
|
Label *done_offset = newLabel(ctx);
|
||||||
|
emitInstr_JUMPIFNOTANDPOP(ctx, done_offset, ifelse->base.offset, ifelse->base.length);
|
||||||
Operand op = { .type = OPTP_PROMISE, .as_promise = done_offset };
|
|
||||||
emitInstr(ctx, OPCODE_JUMPIFNOTANDPOP, &op, 1, ifelse->base.offset, ifelse->base.length);
|
|
||||||
|
|
||||||
emitInstrForNode(ctx, ifelse->true_branch, break_dest);
|
emitInstrForNode(ctx, ifelse->true_branch, break_dest);
|
||||||
|
|
||||||
if(ifelse->true_branch->kind == NODE_EXPR)
|
if(ifelse->true_branch->kind == NODE_EXPR)
|
||||||
emitInstr_POP1(ctx, ifelse->true_branch->offset, 0);
|
emitInstr_POP1(ctx, ifelse->true_branch->offset, 0);
|
||||||
|
setLabelHere(done_offset, ctx);
|
||||||
long long int temp = ExeBuilder_InstrCount(ctx->builder);
|
freeLabel(done_offset);
|
||||||
Promise_Resolve(done_offset, &temp, sizeof(temp));
|
|
||||||
|
|
||||||
Promise_Free(done_offset);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -551,13 +580,10 @@ static void emitInstrForNode(CodegenContext *ctx, Node *node, Promise *break_des
|
|||||||
}
|
}
|
||||||
|
|
||||||
case NODE_BREAK:
|
case NODE_BREAK:
|
||||||
{
|
if(break_dest == NULL)
|
||||||
if(break_dest == NULL)
|
reportErrorAndJump(ctx, 0, "Break not inside a loop");
|
||||||
reportErrorAndJump(ctx, 0, "Break not inside a loop");
|
emitInstr_JUMP(ctx, break_dest, node->offset, node->length);
|
||||||
Operand op = (Operand) { .type = OPTP_PROMISE, .as_promise = break_dest };
|
return;
|
||||||
emitInstr(ctx, OPCODE_JUMP, &op, 1, node->offset, node->length);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
case NODE_IFELSE:
|
case NODE_IFELSE:
|
||||||
emitInstrForIfElseNode(ctx, (IfElseNode*) node, break_dest);
|
emitInstrForIfElseNode(ctx, (IfElseNode*) node, break_dest);
|
||||||
@@ -576,30 +602,18 @@ static void emitInstrForNode(CodegenContext *ctx, Node *node, Promise *break_des
|
|||||||
* end:
|
* end:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Promise *start_offset = newOffsetPromise(ctx);
|
Label *start_offset = newLabel(ctx);
|
||||||
Promise *end_offset = newOffsetPromise(ctx);
|
Label *end_offset = newLabel(ctx);
|
||||||
|
setLabelHere(start_offset, ctx);
|
||||||
long long int temp = ExeBuilder_InstrCount(ctx->builder);
|
|
||||||
Promise_Resolve(start_offset, &temp, sizeof(temp));
|
|
||||||
|
|
||||||
emitInstrForNode(ctx, whl->condition, break_dest);
|
emitInstrForNode(ctx, whl->condition, break_dest);
|
||||||
|
emitInstr_JUMPIFNOTANDPOP(ctx, end_offset, whl->condition->offset, whl->condition->length);
|
||||||
Operand op = { .type = OPTP_PROMISE, .as_promise = end_offset };
|
|
||||||
emitInstr(ctx, OPCODE_JUMPIFNOTANDPOP, &op, 1, whl->condition->offset, whl->condition->length);
|
|
||||||
|
|
||||||
emitInstrForNode(ctx, whl->body, end_offset);
|
emitInstrForNode(ctx, whl->body, end_offset);
|
||||||
|
|
||||||
if(whl->body->kind == NODE_EXPR)
|
if(whl->body->kind == NODE_EXPR)
|
||||||
emitInstr_POP1(ctx, whl->body->offset, 0);
|
emitInstr_POP1(ctx, whl->body->offset, 0);
|
||||||
|
emitInstr_JUMP(ctx, start_offset, node->offset, node->length);
|
||||||
op = (Operand) { .type = OPTP_PROMISE, .as_promise = start_offset };
|
setLabelHere(end_offset, ctx);
|
||||||
emitInstr(ctx, OPCODE_JUMP, &op, 1, node->offset, node->length);
|
freeLabel(start_offset);
|
||||||
|
freeLabel(end_offset);
|
||||||
temp = ExeBuilder_InstrCount(ctx->builder);
|
|
||||||
Promise_Resolve(end_offset, &temp, sizeof(temp));
|
|
||||||
|
|
||||||
Promise_Free(start_offset);
|
|
||||||
Promise_Free(end_offset);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -614,23 +628,15 @@ static void emitInstrForNode(CodegenContext *ctx, Node *node, Promise *break_des
|
|||||||
* JUMPIFANDPOP start
|
* JUMPIFANDPOP start
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Promise *end_offset = newOffsetPromise(ctx);
|
Label *end_offset = newLabel(ctx);
|
||||||
|
|
||||||
long long int start = ExeBuilder_InstrCount(ctx->builder);
|
long long int start = ExeBuilder_InstrCount(ctx->builder);
|
||||||
|
|
||||||
emitInstrForNode(ctx, dowhl->body, end_offset);
|
emitInstrForNode(ctx, dowhl->body, end_offset);
|
||||||
|
|
||||||
if(dowhl->body->kind == NODE_EXPR)
|
if(dowhl->body->kind == NODE_EXPR)
|
||||||
emitInstr_POP1(ctx, dowhl->body->offset, 0);
|
emitInstr_POP1(ctx, dowhl->body->offset, 0);
|
||||||
|
|
||||||
emitInstrForNode(ctx, dowhl->condition, break_dest);
|
emitInstrForNode(ctx, dowhl->condition, break_dest);
|
||||||
|
emitInstr_JUMPIFANDPOP(ctx, start, dowhl->condition->offset, dowhl->condition->length);
|
||||||
Operand op = { .type = OPTP_INT, .as_int = start };
|
setLabelHere(end_offset, ctx);
|
||||||
emitInstr(ctx, OPCODE_JUMPIFANDPOP, &op, 1, dowhl->condition->offset, dowhl->condition->length);
|
freeLabel(end_offset);
|
||||||
|
|
||||||
long long int temp = ExeBuilder_InstrCount(ctx->builder);
|
|
||||||
Promise_Resolve(end_offset, &temp, sizeof(temp));
|
|
||||||
Promise_Free(end_offset);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -643,7 +649,6 @@ static void emitInstrForNode(CodegenContext *ctx, Node *node, Promise *break_des
|
|||||||
while(stmt)
|
while(stmt)
|
||||||
{
|
{
|
||||||
emitInstrForNode(ctx, stmt, break_dest);
|
emitInstrForNode(ctx, stmt, break_dest);
|
||||||
|
|
||||||
if(stmt->kind == NODE_EXPR)
|
if(stmt->kind == NODE_EXPR)
|
||||||
emitInstr_POP1(ctx, stmt->offset, 0);
|
emitInstr_POP1(ctx, stmt->offset, 0);
|
||||||
stmt = stmt->next;
|
stmt = stmt->next;
|
||||||
@@ -662,9 +667,7 @@ static void emitInstrForNode(CodegenContext *ctx, Node *node, Promise *break_des
|
|||||||
|
|
||||||
for(int i = 0; i < count; i += 1)
|
for(int i = 0; i < count; i += 1)
|
||||||
emitInstrForNode(ctx, (Node*) tuple[i], break_dest);
|
emitInstrForNode(ctx, (Node*) tuple[i], break_dest);
|
||||||
|
emitInstr_RETURN(ctx, count, ret->base.offset, ret->base.length);
|
||||||
Operand op = (Operand) { .type = OPTP_INT, .as_int = count };
|
|
||||||
emitInstr(ctx, OPCODE_RETURN, &op, 1, ret->base.offset, ret->base.length);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -725,8 +728,6 @@ Executable *compile(AST *ast, BPAlloc *alloc, Error *error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
emitInstrForNode(&ctx, ast->root, NULL);
|
emitInstrForNode(&ctx, ast->root, NULL);
|
||||||
Operand op = (Operand) { .type = OPTP_INT, .as_int = 0 };
|
emitInstr_RETURN(&ctx, 0, Source_GetSize(ast->src), 0);
|
||||||
emitInstr(&ctx, OPCODE_RETURN, &op, 1, Source_GetSize(ast->src), 0);
|
|
||||||
|
|
||||||
return makeExecutableAndFreeCodegenContext(&ctx, ast->src);
|
return makeExecutableAndFreeCodegenContext(&ctx, ast->src);
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user