refactorin' (incapsulated CodegenContext from codegen.c)

This commit is contained in:
cozis
2022-08-13 17:42:37 +02:00
parent 1ee68745a6
commit ed02bbc9be
7 changed files with 412 additions and 361 deletions
+115 -222
View File
@@ -44,105 +44,13 @@
*/ */
#include <assert.h> #include <assert.h>
#include <setjmp.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h> #include <stdbool.h>
#include "../utils/defs.h" #include "../utils/defs.h"
#include "codegenctx.h"
#include "compile.h" #include "compile.h"
#include "ASTi.h" #include "ASTi.h"
typedef struct {
Error *error;
BPAlloc *alloc;
ExeBuilder *builder;
bool own_alloc;
jmp_buf env;
} 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)
{
longjmp(ctx->env, 1);
}
static void reportErrorAndJump_(CodegenContext *ctx, const char *file,
const char *func, int line, bool internal,
const char *format, ...)
{
va_list args;
va_start(args, format);
_Error_Report2(ctx->error, internal, file, func, line, format, args);
va_end(args);
okNowJump(ctx);
}
#define reportErrorAndJump(ctx, int, fmt, ...) \
reportErrorAndJump_(ctx, __FILE__, __func__, __LINE__, int, fmt, ## __VA_ARGS__)
static void freeCodegenContext(CodegenContext *ctx)
{
if(ctx->own_alloc)
BPAlloc_Free(ctx->alloc);
}
static bool setOrcatchJump(CodegenContext *ctx)
{
bool jumped = setjmp(ctx->env);
return jumped;
}
static bool initCodegenContext(CodegenContext *ctx, Error *error, BPAlloc *alloc)
{
if(alloc == NULL) {
alloc = BPAlloc_Init(-1);
if(alloc == NULL) {
Error_Report(error, 1, "No memory");
return false;
}
ctx->own_alloc = true;
} else {
ctx->own_alloc = false;
}
ExeBuilder *builder = ExeBuilder_New(alloc);
if(builder == NULL) {
if(ctx->own_alloc)
BPAlloc_Free(alloc);
return false;
}
ctx->error = error;
ctx->alloc = alloc;
ctx->builder = builder;
return true;
}
static void emitInstr(CodegenContext *ctx, Opcode opcode, Operand *opv, int opc, int off, int len)
{
if(!ExeBuilder_Append(ctx->builder, ctx->error, opcode, opv, opc, off, len))
okNowJump(ctx);
}
static void emitInstr_POP(CodegenContext *ctx, static void emitInstr_POP(CodegenContext *ctx,
long long int op0, long long int op0,
int off, int len) int off, int len)
@@ -150,7 +58,7 @@ static void emitInstr_POP(CodegenContext *ctx,
Operand opv[1] = { Operand opv[1] = {
{ .type = OPTP_INT, .as_int = op0 } { .type = OPTP_INT, .as_int = op0 }
}; };
emitInstr(ctx, OPCODE_POP, opv, 1, off, len); CodegenContext_EmitInstr(ctx, OPCODE_POP, opv, 1, off, len);
} }
static void emitInstr_POP1(CodegenContext *ctx, int off, int len) static void emitInstr_POP1(CodegenContext *ctx, int off, int len)
@@ -163,7 +71,7 @@ static void emitInstr_ASS(CodegenContext *ctx, const char *name, int off, int le
Operand opv[] = { Operand opv[] = {
{ .type = OPTP_STRING, .as_string = name }, { .type = OPTP_STRING, .as_string = name },
}; };
emitInstr(ctx, OPCODE_ASS, opv, 1, off, len); CodegenContext_EmitInstr(ctx, OPCODE_ASS, opv, 1, off, len);
} }
static void emitInstr_RETURN(CodegenContext *ctx, static void emitInstr_RETURN(CodegenContext *ctx,
@@ -173,27 +81,27 @@ static void emitInstr_RETURN(CodegenContext *ctx,
Operand opv[1] = { Operand opv[1] = {
{ .type = OPTP_INT, .as_int = op0 } { .type = OPTP_INT, .as_int = op0 }
}; };
emitInstr(ctx, OPCODE_RETURN, opv, 1, off, len); CodegenContext_EmitInstr(ctx, OPCODE_RETURN, opv, 1, off, len);
} }
static void emitInstr_JUMP(CodegenContext *ctx, static void emitInstr_JUMP(CodegenContext *ctx,
Promise *op0, Label *op0,
int off, int len) int off, int len)
{ {
Operand opv[1] = { Operand opv[1] = {
{ .type = OPTP_PROMISE, .as_promise = op0 } { .type = OPTP_PROMISE, .as_promise = Label_ToPromise(op0) }
}; };
emitInstr(ctx, OPCODE_JUMP, opv, 1, off, len); CodegenContext_EmitInstr(ctx, OPCODE_JUMP, opv, 1, off, len);
} }
static void emitInstr_JUMPIFNOTANDPOP(CodegenContext *ctx, static void emitInstr_JUMPIFNOTANDPOP(CodegenContext *ctx,
Promise *op0, Label *op0,
int off, int len) int off, int len)
{ {
Operand opv[1] = { Operand opv[1] = {
{ .type = OPTP_PROMISE, .as_promise = op0 } { .type = OPTP_PROMISE, .as_promise = Label_ToPromise(op0) }
}; };
emitInstr(ctx, OPCODE_JUMPIFNOTANDPOP, opv, 1, off, len); CodegenContext_EmitInstr(ctx, OPCODE_JUMPIFNOTANDPOP, opv, 1, off, len);
} }
static void emitInstr_JUMPIFANDPOP(CodegenContext *ctx, static void emitInstr_JUMPIFANDPOP(CodegenContext *ctx,
@@ -203,18 +111,7 @@ static void emitInstr_JUMPIFANDPOP(CodegenContext *ctx,
Operand opv[1] = { Operand opv[1] = {
{ .type = OPTP_INT, .as_int = op0 } { .type = OPTP_INT, .as_int = op0 }
}; };
emitInstr(ctx, OPCODE_JUMPIFANDPOP, opv, 1, off, len); CodegenContext_EmitInstr(ctx, OPCODE_JUMPIFANDPOP, opv, 1, off, len);
}
static Label *newLabel(CodegenContext *ctx)
{
Promise *promise = Promise_New(ctx->alloc, sizeof(long long int));
if(promise != NULL)
return promise;
reportErrorAndJump(ctx, 1, "No memory");
UNREACHABLE;
return NULL; // For the compiler warning.
} }
static void emitInstrForNode(CodegenContext *ctx, Node *node, Label *label_break); static void emitInstrForNode(CodegenContext *ctx, Node *node, Label *label_break);
@@ -262,26 +159,26 @@ static void emitInstrForFuncCallNode(CodegenContext *ctx, CallExprNode *expr,
Operand ops[2]; Operand ops[2];
ops[0] = (Operand) { .type = OPTP_INT, .as_int = expr->argc }; ops[0] = (Operand) { .type = OPTP_INT, .as_int = expr->argc };
ops[1] = (Operand) { .type = OPTP_INT, .as_int = returns }; ops[1] = (Operand) { .type = OPTP_INT, .as_int = returns };
emitInstr(ctx, OPCODE_CALL, ops, 2, expr->base.base.offset, expr->base.base.length); CodegenContext_EmitInstr(ctx, OPCODE_CALL, ops, 2, expr->base.base.offset, expr->base.base.length);
} }
static void emitInstrForFuncNode(CodegenContext *ctx, FunctionNode *func) static void emitInstrForFuncNode(CodegenContext *ctx, FunctionNode *func)
{ {
Label *label_func = newLabel(ctx); Label *label_func = Label_New(ctx);
Label *label_jump = newLabel(ctx); Label *label_jump = Label_New(ctx);
// Push function. // Push function.
{ {
Operand ops[2] = { Operand ops[2] = {
{ .type = OPTP_PROMISE, .as_promise = label_func }, { .type = OPTP_PROMISE, .as_promise = Label_ToPromise(label_func) },
{ .type = OPTP_INT, .as_int = func->argc }, { .type = OPTP_INT, .as_int = func->argc },
}; };
emitInstr(ctx, OPCODE_PUSHFUN, ops, 2, func->base.offset, func->base.length); CodegenContext_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, label_jump, func->base.offset, func->base.length); // Jump after the function code emitInstr_JUMP(ctx, label_jump, func->base.offset, func->base.length); // Jump after the function code
setLabelHere(label_func, ctx); // This is the function code index. Label_SetHere(label_func, ctx); // This is the function code index.
// Compile the function body. // Compile the function body.
{ {
@@ -305,10 +202,10 @@ static void emitInstrForFuncNode(CodegenContext *ctx, FunctionNode *func)
} }
// This is the first index after the function code. // This is the first index after the function code.
setLabelHere(label_jump, ctx); Label_SetHere(label_jump, ctx);
freeLabel(label_func); Label_Free(label_func);
freeLabel(label_jump); Label_Free(label_jump);
} }
static void emitInstrForIfElseNode(CodegenContext *ctx, IfElseNode *ifelse, Label *label_break) static void emitInstrForIfElseNode(CodegenContext *ctx, IfElseNode *ifelse, Label *label_break)
@@ -316,30 +213,30 @@ static void emitInstrForIfElseNode(CodegenContext *ctx, IfElseNode *ifelse, Labe
emitInstrForNode(ctx, ifelse->condition, label_break); emitInstrForNode(ctx, ifelse->condition, label_break);
if(ifelse->false_branch) if(ifelse->false_branch)
{ {
Label *label_else = newLabel(ctx); Label *label_else = Label_New(ctx);
Label *label_done = newLabel(ctx); Label *label_done = Label_New(ctx);
emitInstr_JUMPIFNOTANDPOP(ctx, label_else, ifelse->base.offset, ifelse->base.length); emitInstr_JUMPIFNOTANDPOP(ctx, label_else, ifelse->base.offset, ifelse->base.length);
emitInstrForNode(ctx, ifelse->true_branch, label_break); emitInstrForNode(ctx, ifelse->true_branch, label_break);
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, label_done, ifelse->base.offset, ifelse->base.length); emitInstr_JUMP(ctx, label_done, ifelse->base.offset, ifelse->base.length);
setLabelHere(label_else, ctx); Label_SetHere(label_else, ctx);
emitInstrForNode(ctx, ifelse->false_branch, label_break); emitInstrForNode(ctx, ifelse->false_branch, label_break);
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(label_done, ctx); Label_SetHere(label_done, ctx);
freeLabel(label_else); Label_Free(label_else);
freeLabel(label_done); Label_Free(label_done);
} }
else else
{ {
Label *label_done = newLabel(ctx); Label *label_done = Label_New(ctx);
emitInstr_JUMPIFNOTANDPOP(ctx, label_done, ifelse->base.offset, ifelse->base.length); emitInstr_JUMPIFNOTANDPOP(ctx, label_done, ifelse->base.offset, ifelse->base.length);
emitInstrForNode(ctx, ifelse->true_branch, label_break); emitInstrForNode(ctx, ifelse->true_branch, label_break);
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(label_done, ctx); Label_SetHere(label_done, ctx);
freeLabel(label_done); Label_Free(label_done);
} }
} }
@@ -355,7 +252,7 @@ static void flattenTupleTree(CodegenContext *ctx, ExprNode *root, ExprNode *tupl
if(max == *count) if(max == *count)
{ {
reportErrorAndJump(ctx, 0, "Static buffer is too small"); CodegenContext_ReportErrorAndJump(ctx, 0, "Static buffer is too small");
UNREACHABLE; UNREACHABLE;
} }
@@ -383,7 +280,7 @@ static void emitInstrForAssignmentNode(CodegenContext *ctx, OperExprNode *asgn,
if(((ExprNode*) rop)->kind == EXPR_CALL) if(((ExprNode*) rop)->kind == EXPR_CALL)
emitInstrForFuncCallNode(ctx, (CallExprNode*) rop, label_break, count); emitInstrForFuncCallNode(ctx, (CallExprNode*) rop, label_break, count);
else { else {
reportErrorAndJump(ctx, 0, "Assigning to %d variables only 1 value", count); CodegenContext_ReportErrorAndJump(ctx, 0, "Assigning to %d variables only 1 value", count);
UNREACHABLE; UNREACHABLE;
} }
} }
@@ -406,12 +303,12 @@ static void emitInstrForAssignmentNode(CodegenContext *ctx, OperExprNode *asgn,
Node *set = ((IndexSelectionExprNode*) tuple_item)->set; Node *set = ((IndexSelectionExprNode*) tuple_item)->set;
emitInstrForNode(ctx, set, label_break); emitInstrForNode(ctx, set, label_break);
emitInstrForNode(ctx, idx, label_break); emitInstrForNode(ctx, idx, label_break);
emitInstr(ctx, OPCODE_INSERT2, NULL, 0, tuple_item->base.offset, tuple_item->base.length); CodegenContext_EmitInstr(ctx, OPCODE_INSERT2, NULL, 0, tuple_item->base.offset, tuple_item->base.length);
break; break;
} }
default: default:
reportErrorAndJump(ctx, 0, "Assigning to something that it can't be assigned to"); CodegenContext_ReportErrorAndJump(ctx, 0, "Assigning to something that it can't be assigned to");
UNREACHABLE; UNREACHABLE;
} }
@@ -420,19 +317,57 @@ static void emitInstrForAssignmentNode(CodegenContext *ctx, OperExprNode *asgn,
} }
} }
static void emitInstrForNode(CodegenContext *ctx, Node *node, Label *label_break) static void emitInstrForWhileLoopNode(CodegenContext *ctx, WhileNode *loop, Label *label_break)
{ {
assert(node != NULL); /*
* start:
* <condition>
* JUMPIFNOTANDPOP end
* <body>
* JUMP start
* end:
*/
switch(node->kind) Label *label_start = Label_New(ctx);
Label *label_end = Label_New(ctx);
Label_SetHere(label_start, ctx);
emitInstrForNode(ctx, loop->condition, label_break);
emitInstr_JUMPIFNOTANDPOP(ctx, label_end, loop->condition->offset, loop->condition->length);
emitInstrForNode(ctx, loop->body, label_end);
if(loop->body->kind == NODE_EXPR)
emitInstr_POP1(ctx, loop->body->offset, 0);
emitInstr_JUMP(ctx, label_start, loop->base.offset, loop->base.length);
Label_SetHere(label_end, ctx);
Label_Free(label_start);
Label_Free(label_end);
}
static void emitInstrForDoWhileLoopNode(CodegenContext *ctx, DoWhileNode *loop, Label *label_break)
{ {
case NODE_EXPR: /*
* start:
* <body>
* <condition>
* JUMPIFANDPOP start
*/
Label *label_end = Label_New(ctx);
long long int start = CodegenContext_InstrCount(ctx);
emitInstrForNode(ctx, loop->body, label_end);
if(loop->body->kind == NODE_EXPR)
emitInstr_POP1(ctx, loop->body->offset, 0);
emitInstrForNode(ctx, loop->condition, label_break);
emitInstr_JUMPIFANDPOP(ctx, start, loop->condition->offset, loop->condition->length);
Label_SetHere(label_end, ctx);
Label_Free(label_end);
}
static void emitInstrForExprNode(CodegenContext *ctx, ExprNode *expr, Label *label_break)
{ {
ExprNode *expr = (ExprNode*) node;
switch(expr->kind) switch(expr->kind)
{ {
case EXPR_PAIR: case EXPR_PAIR:
reportErrorAndJump(ctx, 0, "Tuple outside of assignment or return statement"); CodegenContext_ReportErrorAndJump(ctx, 0, "Tuple outside of assignment or return statement");
UNREACHABLE; UNREACHABLE;
return; // For the compiler warning. return; // For the compiler warning.
@@ -455,7 +390,7 @@ static void emitInstrForNode(CodegenContext *ctx, Node *node, Label *label_break
OperExprNode *oper = (OperExprNode*) expr; OperExprNode *oper = (OperExprNode*) expr;
for(Node *operand = oper->head; operand; operand = operand->next) for(Node *operand = oper->head; operand; operand = operand->next)
emitInstrForNode(ctx, operand, label_break); emitInstrForNode(ctx, operand, label_break);
emitInstr(ctx, exprkind_to_opcode(expr->kind), NULL, 0, node->offset, node->length); CodegenContext_EmitInstr(ctx, exprkind_to_opcode(expr->kind), NULL, 0, expr->base.offset, expr->base.length);
return; return;
} }
@@ -467,7 +402,7 @@ static void emitInstrForNode(CodegenContext *ctx, Node *node, Label *label_break
{ {
IntExprNode *p = (IntExprNode*) expr; IntExprNode *p = (IntExprNode*) expr;
Operand op = { .type = OPTP_INT, .as_int = p->val }; Operand op = { .type = OPTP_INT, .as_int = p->val };
emitInstr(ctx, OPCODE_PUSHINT, &op, 1, node->offset, node->length); CodegenContext_EmitInstr(ctx, OPCODE_PUSHINT, &op, 1, expr->base.offset, expr->base.length);
return; return;
} }
@@ -475,7 +410,7 @@ static void emitInstrForNode(CodegenContext *ctx, Node *node, Label *label_break
{ {
FloatExprNode *p = (FloatExprNode*) expr; FloatExprNode *p = (FloatExprNode*) expr;
Operand op = { .type = OPTP_FLOAT, .as_float = p->val }; Operand op = { .type = OPTP_FLOAT, .as_float = p->val };
emitInstr(ctx, OPCODE_PUSHFLT, &op, 1, node->offset, node->length); CodegenContext_EmitInstr(ctx, OPCODE_PUSHFLT, &op, 1, expr->base.offset, expr->base.length);
return; return;
} }
@@ -483,7 +418,7 @@ static void emitInstrForNode(CodegenContext *ctx, Node *node, Label *label_break
{ {
StringExprNode *p = (StringExprNode*) expr; StringExprNode *p = (StringExprNode*) expr;
Operand op = { .type = OPTP_STRING, .as_string = p->val }; Operand op = { .type = OPTP_STRING, .as_string = p->val };
emitInstr(ctx, OPCODE_PUSHSTR, &op, 1, node->offset, node->length); CodegenContext_EmitInstr(ctx, OPCODE_PUSHSTR, &op, 1, expr->base.offset, expr->base.length);
return; return;
} }
@@ -491,7 +426,7 @@ static void emitInstrForNode(CodegenContext *ctx, Node *node, Label *label_break
{ {
IdentExprNode *p = (IdentExprNode*) expr; IdentExprNode *p = (IdentExprNode*) expr;
Operand op = { .type = OPTP_STRING, .as_string = p->val }; Operand op = { .type = OPTP_STRING, .as_string = p->val };
emitInstr(ctx, OPCODE_PUSHVAR, &op, 1, node->offset, node->length); CodegenContext_EmitInstr(ctx, OPCODE_PUSHVAR, &op, 1, expr->base.offset, expr->base.length);
return; return;
} }
@@ -502,12 +437,12 @@ static void emitInstrForNode(CodegenContext *ctx, Node *node, Label *label_break
// <expr> // <expr>
// INSERT // INSERT
ListExprNode *l = (ListExprNode*) node; ListExprNode *l = (ListExprNode*) expr;
Operand op; Operand op;
op = (Operand) { .type = OPTP_INT, .as_int = l->itemc }; op = (Operand) { .type = OPTP_INT, .as_int = l->itemc };
emitInstr(ctx, OPCODE_PUSHLST, &op, 1, node->offset, node->length); CodegenContext_EmitInstr(ctx, OPCODE_PUSHLST, &op, 1, expr->base.offset, expr->base.length);
Node *item = l->items; Node *item = l->items;
int i = 0; int i = 0;
@@ -515,9 +450,9 @@ static void emitInstrForNode(CodegenContext *ctx, Node *node, Label *label_break
while(item) while(item)
{ {
op = (Operand) { .type = OPTP_INT, .as_int = i }; op = (Operand) { .type = OPTP_INT, .as_int = i };
emitInstr(ctx, OPCODE_PUSHINT, &op, 1, item->offset, item->length); CodegenContext_EmitInstr(ctx, OPCODE_PUSHINT, &op, 1, item->offset, item->length);
emitInstrForNode(ctx, item, label_break); emitInstrForNode(ctx, item, label_break);
emitInstr(ctx, OPCODE_INSERT, NULL, 0, item->offset, item->length); CodegenContext_EmitInstr(ctx, OPCODE_INSERT, NULL, 0, item->offset, item->length);
i += 1; i += 1;
item = item->next; item = item->next;
} }
@@ -526,12 +461,12 @@ static void emitInstrForNode(CodegenContext *ctx, Node *node, Label *label_break
case EXPR_MAP: case EXPR_MAP:
{ {
MapExprNode *m = (MapExprNode*) node; MapExprNode *m = (MapExprNode*) expr;
Operand op; Operand op;
op = (Operand) { .type = OPTP_INT, .as_int = m->itemc }; op = (Operand) { .type = OPTP_INT, .as_int = m->itemc };
emitInstr(ctx, OPCODE_PUSHMAP, &op, 1, node->offset, node->length); CodegenContext_EmitInstr(ctx, OPCODE_PUSHMAP, &op, 1, expr->base.offset, expr->base.length);
Node *key = m->keys; Node *key = m->keys;
Node *item = m->items; Node *item = m->items;
@@ -540,7 +475,7 @@ static void emitInstrForNode(CodegenContext *ctx, Node *node, Label *label_break
{ {
emitInstrForNode(ctx, key, label_break); emitInstrForNode(ctx, key, label_break);
emitInstrForNode(ctx, item, label_break); emitInstrForNode(ctx, item, label_break);
emitInstr(ctx, OPCODE_INSERT, NULL, 0, item->offset, item->length); CodegenContext_EmitInstr(ctx, OPCODE_INSERT, NULL, 0, item->offset, item->length);
key = key->next; key = key->next;
item = item->next; item = item->next;
} }
@@ -556,32 +491,41 @@ static void emitInstrForNode(CodegenContext *ctx, Node *node, Label *label_break
IndexSelectionExprNode *sel = (IndexSelectionExprNode*) expr; IndexSelectionExprNode *sel = (IndexSelectionExprNode*) expr;
emitInstrForNode(ctx, sel->set, label_break); emitInstrForNode(ctx, sel->set, label_break);
emitInstrForNode(ctx, sel->idx, label_break); emitInstrForNode(ctx, sel->idx, label_break);
emitInstr(ctx, OPCODE_SELECT, NULL, 0, node->offset, node->length); CodegenContext_EmitInstr(ctx, OPCODE_SELECT, NULL, 0, expr->base.offset, expr->base.length);
return; return;
} }
case EXPR_NONE: case EXPR_NONE:
emitInstr(ctx, OPCODE_PUSHNNE, NULL, 0, node->offset, node->length); CodegenContext_EmitInstr(ctx, OPCODE_PUSHNNE, NULL, 0, expr->base.offset, expr->base.length);
return; return;
case EXPR_TRUE: case EXPR_TRUE:
emitInstr(ctx, OPCODE_PUSHTRU, NULL, 0, node->offset, node->length); CodegenContext_EmitInstr(ctx, OPCODE_PUSHTRU, NULL, 0, expr->base.offset, expr->base.length);
return; return;
case EXPR_FALSE: case EXPR_FALSE:
emitInstr(ctx, OPCODE_PUSHFLS, NULL, 0, node->offset, node->length); CodegenContext_EmitInstr(ctx, OPCODE_PUSHFLS, NULL, 0, expr->base.offset, expr->base.length);
return; return;
default: default:
UNREACHABLE; UNREACHABLE;
break; break;
} }
return;
} }
static void emitInstrForNode(CodegenContext *ctx, Node *node, Label *label_break)
{
assert(node != NULL);
switch(node->kind)
{
case NODE_EXPR:
emitInstrForExprNode(ctx, (ExprNode*) node, label_break);
return;
case NODE_BREAK: case NODE_BREAK:
if(label_break == NULL) if(label_break == NULL)
reportErrorAndJump(ctx, 0, "Break not inside a loop"); CodegenContext_ReportErrorAndJump(ctx, 0, "Break not inside a loop");
emitInstr_JUMP(ctx, label_break, node->offset, node->length); emitInstr_JUMP(ctx, label_break, node->offset, node->length);
return; return;
@@ -590,54 +534,12 @@ static void emitInstrForNode(CodegenContext *ctx, Node *node, Label *label_break
return; return;
case NODE_WHILE: case NODE_WHILE:
{ emitInstrForWhileLoopNode(ctx, (WhileNode*) node, label_break);
WhileNode *whl = (WhileNode*) node;
/*
* start:
* <condition>
* JUMPIFNOTANDPOP end
* <body>
* JUMP start
* end:
*/
Label *label_start = newLabel(ctx);
Label *label_end = newLabel(ctx);
setLabelHere(label_start, ctx);
emitInstrForNode(ctx, whl->condition, label_break);
emitInstr_JUMPIFNOTANDPOP(ctx, label_end, whl->condition->offset, whl->condition->length);
emitInstrForNode(ctx, whl->body, label_end);
if(whl->body->kind == NODE_EXPR)
emitInstr_POP1(ctx, whl->body->offset, 0);
emitInstr_JUMP(ctx, label_start, node->offset, node->length);
setLabelHere(label_end, ctx);
freeLabel(label_start);
freeLabel(label_end);
return; return;
}
case NODE_DOWHILE: case NODE_DOWHILE:
{ emitInstrForDoWhileLoopNode(ctx, (DoWhileNode*) node, label_break);
DoWhileNode *dowhl = (DoWhileNode*) node;
/*
* start:
* <body>
* <condition>
* JUMPIFANDPOP start
*/
Label *label_end = newLabel(ctx);
long long int start = ExeBuilder_InstrCount(ctx->builder);
emitInstrForNode(ctx, dowhl->body, label_end);
if(dowhl->body->kind == NODE_EXPR)
emitInstr_POP1(ctx, dowhl->body->offset, 0);
emitInstrForNode(ctx, dowhl->condition, label_break);
emitInstr_JUMPIFANDPOP(ctx, start, dowhl->condition->offset, dowhl->condition->length);
setLabelHere(label_end, ctx);
freeLabel(label_end);
return; return;
}
case NODE_COMP: case NODE_COMP:
{ {
@@ -680,17 +582,6 @@ static void emitInstrForNode(CodegenContext *ctx, Node *node, Label *label_break
UNREACHABLE; UNREACHABLE;
} }
static Executable *makeExecutableAndFreeCodegenContext(CodegenContext *ctx, Source *src)
{
Executable *exe = ExeBuilder_Finalize(ctx->builder, ctx->error);
if(exe == NULL)
okNowJump(ctx);
Executable_SetSource(exe, src);
freeCodegenContext(ctx);
return exe;
}
/* Symbol: codegen /* Symbol: codegen
* *
* Serializes an AST into bytecode format. * Serializes an AST into bytecode format.
@@ -716,17 +607,19 @@ Executable *codegen(AST *ast, BPAlloc *alloc, Error *error)
assert(ast != NULL); assert(ast != NULL);
assert(error != NULL); assert(error != NULL);
CodegenContext ctx; CodegenContext *ctx = CodegenContext_New(error, alloc);
if(!initCodegenContext(&ctx, error, alloc)) if(ctx == NULL) {
Error_Report(error, 1, "No memory");
return NULL; return NULL;
}
bool jumped = setOrcatchJump(&ctx); bool jumped = CodegenContext_SetOrCatchJump(ctx);
if(jumped) { if(jumped) {
freeCodegenContext(&ctx); CodegenContext_Free(ctx);
return NULL; return NULL;
} }
emitInstrForNode(&ctx, ast->root, NULL); emitInstrForNode(ctx, ast->root, NULL);
emitInstr_RETURN(&ctx, 0, Source_GetSize(ast->src), 0); emitInstr_RETURN(ctx, 0, Source_GetSize(ast->src), 0);
return makeExecutableAndFreeCodegenContext(&ctx, ast->src); return CodegenContext_MakeExecutableAndFree(ctx, ast->src);
} }
+137
View File
@@ -0,0 +1,137 @@
#include <setjmp.h>
#include <stdbool.h>
#include "../utils/defs.h"
#include "codegenctx.h"
struct CodegenContext {
Error *error;
BPAlloc *alloc;
ExeBuilder *builder;
bool own_alloc;
jmp_buf env;
};
Label *Label_New(CodegenContext *ctx)
{
Promise *promise = Promise_New(ctx->alloc, sizeof(long long int));
if(promise != NULL)
return (Label*) promise;
CodegenContext_ReportErrorAndJump(ctx, 1, "No memory");
UNREACHABLE;
return NULL; // For the compiler warning.
}
void Label_Set(Label *label, long long int value)
{
Promise *promise = (Promise*) label;
Promise_Resolve(promise, &value, sizeof(value));
}
void Label_SetHere(Label *label, CodegenContext *ctx)
{
long long int value = ExeBuilder_InstrCount(ctx->builder);
Label_Set(label, value);
}
void Label_Free(Label *label)
{
Promise *promise = (Promise*) label;
Promise_Free(promise);
}
Promise *Label_ToPromise(Label *label)
{
Promise *promise = (Promise*) label;
return promise;
}
static void okNowJump(CodegenContext *ctx)
{
longjmp(ctx->env, 1);
}
void CodegenContext_ReportErrorAndJump_(CodegenContext *ctx, const char *file,
const char *func, int line, bool internal,
const char *format, ...)
{
va_list args;
va_start(args, format);
_Error_Report2(ctx->error, internal, file, func, line, format, args);
va_end(args);
okNowJump(ctx);
}
_Bool CodegenContext_SetOrCatchJump(CodegenContext *ctx)
{
bool jumped = setjmp(ctx->env);
return jumped;
}
CodegenContext *CodegenContext_New(Error *error, BPAlloc *alloc)
{
bool own_alloc;
if(alloc == NULL) {
alloc = BPAlloc_Init(-1);
if(alloc == NULL) {
Error_Report(error, 1, "No memory");
return false;
}
own_alloc = true;
} else {
own_alloc = false;
}
CodegenContext *ctx = BPAlloc_Malloc(alloc, sizeof(CodegenContext));
if(ctx == NULL) {
if(own_alloc)
BPAlloc_Free(alloc);
Error_Report(error, 1, "No memory");
return NULL;
}
ExeBuilder *builder = ExeBuilder_New(alloc);
if(builder == NULL) {
if(ctx->own_alloc)
BPAlloc_Free(alloc);
return NULL;
}
ctx->error = error;
ctx->alloc = alloc;
ctx->builder = builder;
ctx->own_alloc = own_alloc;
return ctx;
}
int CodegenContext_InstrCount(CodegenContext *ctx)
{
return ExeBuilder_InstrCount(ctx->builder);
}
void CodegenContext_Free(CodegenContext *ctx)
{
if(ctx->own_alloc)
BPAlloc_Free(ctx->alloc);
}
Executable *CodegenContext_MakeExecutableAndFree(CodegenContext *ctx, Source *src)
{
Executable *exe = ExeBuilder_Finalize(ctx->builder, ctx->error);
if(exe == NULL)
okNowJump(ctx);
if(src != NULL)
Executable_SetSource(exe, src);
CodegenContext_Free(ctx);
return exe;
}
void CodegenContext_EmitInstr(CodegenContext *ctx, Opcode opcode, Operand *opv, int opc, int off, int len)
{
if(!ExeBuilder_Append(ctx->builder, ctx->error, opcode, opv, opc, off, len))
okNowJump(ctx);
}
+22
View File
@@ -0,0 +1,22 @@
#ifndef CODEGENCTX_H
#define CODEGENCTX_H
#include "../common/executable.h"
typedef struct CodegenContext CodegenContext;
CodegenContext *CodegenContext_New(Error *error, BPAlloc *alloc);
void CodegenContext_EmitInstr(CodegenContext *ctx, Opcode opcode, Operand *opv, int opc, int off, int len);
_Bool CodegenContext_SetOrCatchJump(CodegenContext *ctx);
void CodegenContext_Free(CodegenContext *ctx);
Executable *CodegenContext_MakeExecutableAndFree(CodegenContext *ctx, Source *src);
void CodegenContext_ReportErrorAndJump_(CodegenContext *ctx, const char *file, const char *func, int line, bool internal, const char *format, ...);
#define CodegenContext_ReportErrorAndJump(ctx, int, fmt, ...) CodegenContext_ReportErrorAndJump_(ctx, __FILE__, __func__, __LINE__, int, fmt, ## __VA_ARGS__)
int CodegenContext_InstrCount(CodegenContext *ctx);
typedef struct Label Label;
Label *Label_New(CodegenContext *ctx);
void Label_Set(Label *label, long long int value);
void Label_SetHere(Label *label, CodegenContext *ctx);
void Label_Free(Label *label);
Promise *Label_ToPromise(Label *label);
#endif /* CODEGENCTX_H */
+2 -2
View File
@@ -32,10 +32,10 @@ Executable *compile(Source *src, Error *error, CompilationErrorType *errtyp)
return NULL; return NULL;
} }
// Transform the AST into bytecode.
Executable *exe = codegen(ast, alloc, error); Executable *exe = codegen(ast, alloc, error);
// We're done with the AST, independently from // We're done with the AST.
// the compilation result.
BPAlloc_Free(alloc); BPAlloc_Free(alloc);
if(exe == NULL) if(exe == NULL)
+1 -1
View File
@@ -445,7 +445,7 @@ AST *parse(Source *src, BPAlloc *alloc, Error *error)
if(root == NULL) if(root == NULL)
return NULL; return NULL;
ast->src = src; // Not copying! Be sure to not free the source before the AST! ast->src = src; // Not copying! Be sure not to free the source before the AST!
ast->root = root; ast->root = root;
if(ast->src == NULL) if(ast->src == NULL)
-1
View File
@@ -2,7 +2,6 @@
#include <assert.h> #include <assert.h>
#include "utils/error.h" #include "utils/error.h"
#include "utils/source.h" #include "utils/source.h"
#include "compiler/parse.h"
#include "compiler/compile.h" #include "compiler/compile.h"
#include "assembler/assemble.h" #include "assembler/assemble.h"
#include "builtins/basic.h" #include "builtins/basic.h"