adding compilation of if-else statements
This commit is contained in:
+71
-2
@@ -42,7 +42,8 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error)
|
||||
OperExprNode *oper = (OperExprNode*) expr;
|
||||
|
||||
for(Node *operand = oper->head; operand; operand = operand->next)
|
||||
emit_instr_for_node(exeb, operand, error);
|
||||
if(!emit_instr_for_node(exeb, operand, error))
|
||||
return 0;
|
||||
|
||||
return ExeBuilder_Append(exeb, error,
|
||||
exprkind_to_opcode(expr->kind),
|
||||
@@ -84,10 +85,78 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error)
|
||||
break;
|
||||
}
|
||||
|
||||
case NODE_IFELSE:
|
||||
{
|
||||
IfElseNode *ifelse = (IfElseNode*) node;
|
||||
|
||||
if(!emit_instr_for_node(exeb, ifelse->condition, error))
|
||||
return 0;
|
||||
|
||||
if(ifelse->false_branch)
|
||||
{
|
||||
Promise *else_offset = Promise_New(ExeBuilder_GetAlloc(exeb), sizeof(long long int));
|
||||
Promise *done_offset = Promise_New(ExeBuilder_GetAlloc(exeb), sizeof(long long int));
|
||||
|
||||
if(else_offset == NULL || done_offset == NULL)
|
||||
{
|
||||
Error_Report(error, 1, "No memory");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Operand op = { .type = OPTP_PROMISE, .as_promise = else_offset };
|
||||
if(!ExeBuilder_Append(exeb, error, OPCODE_JUMPIFNOTANDPOP, &op, 1, node->offset, node->length))
|
||||
return 0;
|
||||
|
||||
if(!emit_instr_for_node(exeb, ifelse->true_branch, error))
|
||||
return 0;
|
||||
|
||||
op = (Operand) { .type = OPTP_PROMISE, .as_promise = done_offset };
|
||||
if(!ExeBuilder_Append(exeb, error, OPCODE_JUMP, &op, 1, node->offset, node->length))
|
||||
return 0;
|
||||
|
||||
long long int temp = ExeBuilder_InstrCount(exeb);
|
||||
Promise_Resolve(else_offset, &temp, sizeof(temp));
|
||||
|
||||
if(!emit_instr_for_node(exeb, ifelse->false_branch, error))
|
||||
return 0;
|
||||
|
||||
temp = ExeBuilder_InstrCount(exeb);
|
||||
Promise_Resolve(done_offset, &temp, sizeof(temp));
|
||||
|
||||
Promise_Free(else_offset);
|
||||
Promise_Free(done_offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
Promise *done_offset = Promise_New(ExeBuilder_GetAlloc(exeb), sizeof(long long int));
|
||||
|
||||
if(done_offset == NULL)
|
||||
{
|
||||
Error_Report(error, 1, "No memory");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!ExeBuilder_Append(exeb, error, OPCODE_JUMPIFNOTANDPOP, &(Operand) { .type = OPTP_PROMISE, .as_promise = done_offset }, 1, node->offset, node->length))
|
||||
return 0;
|
||||
|
||||
if(!emit_instr_for_node(exeb, ifelse->true_branch, error))
|
||||
return 0;
|
||||
|
||||
long long int temp = ExeBuilder_InstrCount(exeb);
|
||||
Promise_Resolve(done_offset, &temp, sizeof(temp));
|
||||
|
||||
Promise_Free(done_offset);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
default:
|
||||
UNREACHABLE;
|
||||
break;
|
||||
return 0;
|
||||
}
|
||||
UNREACHABLE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Executable *compile(AST *ast, BPAlloc *alloc, Error *error)
|
||||
|
||||
+30
-14
@@ -369,7 +369,7 @@ static Node *parse_string_primary_expression(Context *ctx)
|
||||
assert(ctx != NULL);
|
||||
assert(ctx->token->kind == TSTRING);
|
||||
|
||||
if(current(ctx) == TDONE)
|
||||
if(done(ctx))
|
||||
{
|
||||
Error_Report(ctx->error, 0, "Source ended where a string literal was expected");
|
||||
return NULL;
|
||||
@@ -493,6 +493,12 @@ static Node *parse_primary_expresion(Context *ctx)
|
||||
{
|
||||
assert(ctx != NULL);
|
||||
|
||||
if(done(ctx))
|
||||
{
|
||||
Error_Report(ctx->error, 0, "Source ended where a primary expression was expected");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch(current(ctx))
|
||||
{
|
||||
case '+':
|
||||
@@ -532,7 +538,7 @@ static Node *parse_primary_expresion(Context *ctx)
|
||||
if(node == NULL)
|
||||
return NULL;
|
||||
|
||||
if(current(ctx) == TDONE)
|
||||
if(done(ctx))
|
||||
{
|
||||
Error_Report(ctx->error, 0, "Source ended before \")\", after sub-expression");
|
||||
return NULL;
|
||||
@@ -823,34 +829,44 @@ static Node *parse_ifelse_statement(Context *ctx)
|
||||
{
|
||||
assert(ctx != NULL);
|
||||
assert(ctx->token != NULL);
|
||||
assert(ctx->token->kind == TKWIF);
|
||||
|
||||
ctx->token = ctx->token->next;
|
||||
|
||||
if(ctx->token->kind == TDONE)
|
||||
if(done(ctx))
|
||||
{
|
||||
// ERROR: Source ended after if keyword.
|
||||
// An expression was expected.
|
||||
Error_Report(ctx->error, 0, "Source ended after if keyword. An expression was expected");
|
||||
Error_Report(ctx->error, 0, "Source ended where an if-else statement was expected");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(current(ctx) != TKWIF)
|
||||
{
|
||||
Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" where an if-else statement was expected", ctx->token->length, ctx->src + ctx->token->offset);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Token *if_token = current_token(ctx);
|
||||
assert(if_token != NULL);
|
||||
|
||||
next(ctx); // Consume the "if" keyword.
|
||||
|
||||
Node *condition = parse_expression(ctx);
|
||||
if(condition == NULL) return NULL;
|
||||
|
||||
if(condition == NULL)
|
||||
return NULL;
|
||||
|
||||
Node *true_branch = parse_statement(ctx);
|
||||
if(condition == NULL) return NULL;
|
||||
|
||||
if(condition == NULL)
|
||||
return NULL;
|
||||
|
||||
Node *false_branch = NULL;
|
||||
|
||||
if(ctx->token->kind == TKWELSE)
|
||||
{
|
||||
// Consume the "else" token.
|
||||
ctx->token = ctx->token->next;
|
||||
next(ctx); // Consume the "else" token.
|
||||
|
||||
false_branch = parse_statement(ctx);
|
||||
if(false_branch == NULL) return NULL;
|
||||
|
||||
if(false_branch == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
IfElseNode *ifelse;
|
||||
|
||||
@@ -126,6 +126,27 @@ static xj_value *convert_node(Node *node, xj_error *error, xj_alloc **alloc)
|
||||
}
|
||||
break;
|
||||
|
||||
case NODE_IFELSE:
|
||||
{
|
||||
IfElseNode *ifelse = (IfElseNode*) node;
|
||||
|
||||
xj_value *condition = convert_node(ifelse->condition, error, alloc);
|
||||
if(condition == NULL) return NULL;
|
||||
|
||||
xj_value *true_branch = convert_node(ifelse->true_branch, error, alloc);
|
||||
if(true_branch == NULL) return NULL;
|
||||
|
||||
xj_value *false_branch = convert_node(ifelse->false_branch, error, alloc);
|
||||
if(false_branch == NULL) return NULL;
|
||||
|
||||
return xj_decodef(error, alloc,
|
||||
"{"
|
||||
"\t\"node-kind\": \"if-else\", \n"
|
||||
"\t\"condition\": %v, \n"
|
||||
"\t\"true-branch\": %v, \n"
|
||||
"\t\"false-branch\": %v\n"
|
||||
"}", condition, true_branch, false_branch);
|
||||
}
|
||||
|
||||
default:
|
||||
UNREACHABLE;
|
||||
|
||||
Reference in New Issue
Block a user