adding compilation of if-else statements

This commit is contained in:
cozis
2021-10-31 07:01:15 +00:00
parent 5e8fb7ef6b
commit 9eaa82297f
16 changed files with 269 additions and 25 deletions
+1
View File
@@ -1 +1,2 @@
build build
temp
+2
View File
@@ -0,0 +1,2 @@
if 1 1;
+22 -4
View File
@@ -48,12 +48,15 @@ static const InstrInfo instr_table[] = {
[OPCODE_MUL] = {"MUL", 2, 0, NULL}, [OPCODE_MUL] = {"MUL", 2, 0, NULL},
[OPCODE_DIV] = {"DIV", 2, 0, NULL}, [OPCODE_DIV] = {"DIV", 2, 0, NULL},
[OPCODE_PUSHI] = {"PUSHI", 2, 1, (OperandType[]) {OPTP_INT}}, [OPCODE_PUSHI] = {"PUSHI", 1, 1, (OperandType[]) {OPTP_INT}},
[OPCODE_PUSHF] = {"PUSHF", 2, 1, (OperandType[]) {OPTP_FLOAT}}, [OPCODE_PUSHF] = {"PUSHF", 1, 1, (OperandType[]) {OPTP_FLOAT}},
[OPCODE_PUSHS] = {"PUSHS", 2, 1, (OperandType[]) {OPTP_STRING}}, [OPCODE_PUSHS] = {"PUSHS", 1, 1, (OperandType[]) {OPTP_STRING}},
[OPCODE_PUSHV] = {"PUSHV", 2, 1, (OperandType[]) {OPTP_STRING}}, [OPCODE_PUSHV] = {"PUSHV", 1, 1, (OperandType[]) {OPTP_STRING}},
[OPCODE_RETURN] = {"RETURN", 0, 0, NULL}, [OPCODE_RETURN] = {"RETURN", 0, 0, NULL},
[OPCODE_JUMPIFNOTANDPOP] = {"JUMPIFNOTANDPOP", 1, 1, (OperandType[]) {OPTP_INT}},
[OPCODE_JUMP] = {"JUMP", 0, 1, (OperandType[]) {OPTP_INT}},
}; };
static const char *operand_type_names[] = { static const char *operand_type_names[] = {
@@ -363,3 +366,18 @@ _Bool ExeBuilder_Append(ExeBuilder *exeb, Error *error, Opcode opcode, Operand *
return 1; return 1;
} }
BPAlloc *ExeBuilder_GetAlloc(ExeBuilder *exeb)
{
return BucketList_GetAlloc(exeb->code);
}
int ExeBuilder_InstrCount(ExeBuilder *exeb)
{
int raw_size = BucketList_Size(exeb->code);
assert(raw_size % sizeof(Instruction) == 0);
return raw_size / sizeof(Instruction);
}
+4
View File
@@ -33,6 +33,8 @@ typedef enum {
OPCODE_PUSHS, OPCODE_PUSHS,
OPCODE_PUSHV, OPCODE_PUSHV,
OPCODE_RETURN, OPCODE_RETURN,
OPCODE_JUMPIFNOTANDPOP,
OPCODE_JUMP,
} Opcode; } Opcode;
typedef struct xExecutable Executable; typedef struct xExecutable Executable;
@@ -47,4 +49,6 @@ Source *Executable_GetSource(Executable *exe);
ExeBuilder *ExeBuilder_New(BPAlloc *alloc); ExeBuilder *ExeBuilder_New(BPAlloc *alloc);
_Bool ExeBuilder_Append(ExeBuilder *exeb, Error *error, Opcode opcode, Operand *opv, int opc, int off, int len); _Bool ExeBuilder_Append(ExeBuilder *exeb, Error *error, Opcode opcode, Operand *opv, int opc, int off, int len);
Executable *ExeBuilder_Finalize(ExeBuilder *exeb, Error *error); Executable *ExeBuilder_Finalize(ExeBuilder *exeb, Error *error);
BPAlloc *ExeBuilder_GetAlloc(ExeBuilder *exeb);
int ExeBuilder_InstrCount(ExeBuilder *exeb);
#endif #endif
+71 -2
View File
@@ -42,7 +42,8 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error)
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)
emit_instr_for_node(exeb, operand, error); if(!emit_instr_for_node(exeb, operand, error))
return 0;
return ExeBuilder_Append(exeb, error, return ExeBuilder_Append(exeb, error,
exprkind_to_opcode(expr->kind), exprkind_to_opcode(expr->kind),
@@ -84,10 +85,78 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error)
break; 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: default:
UNREACHABLE; UNREACHABLE;
break; return 0;
} }
UNREACHABLE;
return 0;
} }
Executable *compile(AST *ast, BPAlloc *alloc, Error *error) Executable *compile(AST *ast, BPAlloc *alloc, Error *error)
+30 -14
View File
@@ -369,7 +369,7 @@ static Node *parse_string_primary_expression(Context *ctx)
assert(ctx != NULL); assert(ctx != NULL);
assert(ctx->token->kind == TSTRING); 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"); Error_Report(ctx->error, 0, "Source ended where a string literal was expected");
return NULL; return NULL;
@@ -493,6 +493,12 @@ static Node *parse_primary_expresion(Context *ctx)
{ {
assert(ctx != NULL); assert(ctx != NULL);
if(done(ctx))
{
Error_Report(ctx->error, 0, "Source ended where a primary expression was expected");
return NULL;
}
switch(current(ctx)) switch(current(ctx))
{ {
case '+': case '+':
@@ -532,7 +538,7 @@ static Node *parse_primary_expresion(Context *ctx)
if(node == NULL) if(node == NULL)
return NULL; return NULL;
if(current(ctx) == TDONE) if(done(ctx))
{ {
Error_Report(ctx->error, 0, "Source ended before \")\", after sub-expression"); Error_Report(ctx->error, 0, "Source ended before \")\", after sub-expression");
return NULL; return NULL;
@@ -823,34 +829,44 @@ static Node *parse_ifelse_statement(Context *ctx)
{ {
assert(ctx != NULL); assert(ctx != NULL);
assert(ctx->token != NULL); assert(ctx->token != NULL);
assert(ctx->token->kind == TKWIF);
ctx->token = ctx->token->next; if(done(ctx))
if(ctx->token->kind == TDONE)
{ {
// ERROR: Source ended after if keyword. Error_Report(ctx->error, 0, "Source ended where an if-else statement was expected");
// An expression was expected. return NULL;
Error_Report(ctx->error, 0, "Source ended after if keyword. An expression was expected"); }
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; return NULL;
} }
Token *if_token = current_token(ctx); Token *if_token = current_token(ctx);
assert(if_token != NULL);
next(ctx); // Consume the "if" keyword.
Node *condition = parse_expression(ctx); Node *condition = parse_expression(ctx);
if(condition == NULL) return NULL;
if(condition == NULL)
return NULL;
Node *true_branch = parse_statement(ctx); Node *true_branch = parse_statement(ctx);
if(condition == NULL) return NULL;
if(condition == NULL)
return NULL;
Node *false_branch = NULL; Node *false_branch = NULL;
if(ctx->token->kind == TKWELSE) if(ctx->token->kind == TKWELSE)
{ {
// Consume the "else" token. next(ctx); // Consume the "else" token.
ctx->token = ctx->token->next;
false_branch = parse_statement(ctx); false_branch = parse_statement(ctx);
if(false_branch == NULL) return NULL;
if(false_branch == NULL)
return NULL;
} }
IfElseNode *ifelse; IfElseNode *ifelse;
+21
View File
@@ -126,6 +126,27 @@ static xj_value *convert_node(Node *node, xj_error *error, xj_alloc **alloc)
} }
break; 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: default:
UNREACHABLE; UNREACHABLE;
+38
View File
@@ -0,0 +1,38 @@
#include <assert.h>
#include <string.h>
#include "objects.h"
static _Bool to_bool(Object *obj, Error *err);
static const Type t_int = {
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
.name = "int",
.size = sizeof (Object),
.atomic = ATMTP_BOOL,
.to_bool = to_bool,
};
static Object the_true_object = {
.type = t_bool,
.flags = Object_STATIC,
}
static Object the_false_object = {
.type = t_bool,
.flags = Object_STATIC,
}
static _Bool to_bool(Object *obj, Error *err)
{
assert(obj);
assert(err);
assert(Object_GetType(obj) == &t_bool);
return obj == &the_true_object;
}
Object *Object_FromBool(_Bool val, Heap *heap, Error *error)
{
(void) heap;
(void) error;
return val ? &the_true_object : &the_false_object;
}
+30
View File
@@ -218,6 +218,13 @@ _Bool Object_IsInt(Object *obj)
return obj->type->atomic == ATMTP_INT; return obj->type->atomic == ATMTP_INT;
} }
_Bool Object_IsBool(Object *obj)
{
assert(obj != NULL);
assert(obj->type != NULL);
return obj->type->atomic == ATMTP_BOOL;
}
_Bool Object_IsFloat(Object *obj) _Bool Object_IsFloat(Object *obj)
{ {
assert(obj != NULL); assert(obj != NULL);
@@ -248,6 +255,29 @@ long long int Object_ToInt(Object *obj, Error *err)
return type->to_int(obj, err); return type->to_int(obj, err);
} }
_Bool Object_ToBool(Object *obj, Error *err)
{
assert(err);
assert(obj);
if(!Object_IsBool(obj))
{
Error_Report(err, 0, "Object is not a boolean");
return 0;
}
const Type *type = Object_GetType(obj);
assert(type);
if(type->to_bool == NULL)
{
Error_Report(err, "Object %s doesn't implement %s", Object_GetName(obj), __func__);
return 0;
}
return type->to_bool(obj, err);
}
double Object_ToFloat(Object *obj, Error *err) double Object_ToFloat(Object *obj, Error *err)
{ {
assert(err); assert(err);
+5
View File
@@ -15,6 +15,7 @@ struct Object {
typedef enum { typedef enum {
ATMTP_NOTATOMIC = 0, ATMTP_NOTATOMIC = 0,
ATMTP_INT, ATMTP_INT,
ATMTP_BOOL,
ATMTP_FLOAT, ATMTP_FLOAT,
} AtomicType; } AtomicType;
@@ -47,6 +48,7 @@ struct Type {
// Some. // Some.
union { union {
long long int (*to_int)(Object *self, Error *err); long long int (*to_int)(Object *self, Error *err);
_Bool (*to_bool)(Object *self, Error *err);
double (*to_float)(Object *self, Error *err); double (*to_float)(Object *self, Error *err);
char *(*to_string)(Object *self, int *size, Heap *heap, Error *err); char *(*to_string)(Object *self, int *size, Heap *heap, Error *err);
}; };
@@ -81,13 +83,16 @@ Object* Object_NewMap(int num, Heap *heap, Error *error);
Object* Object_NewNone(Heap *heap, Error *error); Object* Object_NewNone(Heap *heap, Error *error);
Object* Object_FromInt (long long int val, Heap *heap, Error *error); Object* Object_FromInt (long long int val, Heap *heap, Error *error);
Object* Object_FromBool (_Bool val, Heap *heap, Error *error);
Object* Object_FromFloat (double val, Heap *heap, Error *error); Object* Object_FromFloat (double val, Heap *heap, Error *error);
Object* Object_FromString(const char *str, int len, Heap *heap, Error *error); Object* Object_FromString(const char *str, int len, Heap *heap, Error *error);
_Bool Object_IsInt (Object *obj); _Bool Object_IsInt (Object *obj);
_Bool Object_IsBool (Object *obj);
_Bool Object_IsFloat(Object *obj); _Bool Object_IsFloat(Object *obj);
long long int Object_ToInt (Object *obj, Error *err); long long int Object_ToInt (Object *obj, Error *err);
_Bool Object_ToBool (Object *obj, Error *err);
double Object_ToFloat(Object *obj, Error *err); double Object_ToFloat(Object *obj, Error *err);
_Bool Object_Compare(Object *obj1, Object *obj2, Error *error); _Bool Object_Compare(Object *obj1, Object *obj2, Error *error);
+34
View File
@@ -433,6 +433,40 @@ static _Bool step(Runtime *runtime, Error *error)
case OPCODE_RETURN: case OPCODE_RETURN:
return 0; return 0;
case OPCODE_JUMP:
assert(opc == 1);
assert(ops[0].type == OPTP_INT);
runtime->frame->index = ops[0].as_int;
return 1;
case OPCODE_JUMPIFNOTANDPOP:
{
assert(opc == 1);
assert(ops[0].type == OPTP_INT);
long long int target = ops[0].as_int;
if(runtime->frame->used == 0)
{
Error_Report(error, 1, "Frame doesn't have enough items on the stack to execute JUMPIFNOTANDPOP");
return 0;
}
Object *top = Stack_Top(runtime->stack, 0);
assert(top != NULL);
if(!Object_IsBool(top))
{
Error_Report(error, 1, "JUMPIFNOTANDPOP expected a boolean on the stack");
return 0;
}
if(Object_ToBool(top, error)) // This can't fail because we know it's a bool.
runtime->frame->index = target;
return 1;
}
default: default:
UNREACHABLE; UNREACHABLE;
return 0; return 0;
+5
View File
@@ -175,3 +175,8 @@ void BucketList_Copy(BucketList *blist, void *dest, int len)
bucket = bucket->next; bucket = bucket->next;
} }
} }
BPAlloc *BucketList_GetAlloc(BucketList *blist)
{
return blist->alloc;
}
+1
View File
@@ -7,4 +7,5 @@ int BucketList_Size(BucketList *blist);
void BucketList_Copy(BucketList *blist, void *dest, int len); void BucketList_Copy(BucketList *blist, void *dest, int len);
_Bool BucketList_Append (BucketList *blist, const void *data, int size); _Bool BucketList_Append (BucketList *blist, const void *data, int size);
void *BucketList_Append2(BucketList *blist, const void *data, int size); void *BucketList_Append2(BucketList *blist, const void *data, int size);
BPAlloc *BucketList_GetAlloc(BucketList *blist);
#endif #endif
+1 -1
View File
@@ -41,7 +41,7 @@ unsigned int Promise_Size(Promise *promise)
return promise->size; return promise->size;
} }
void Promise_Delete(Promise *promise) void Promise_Free(Promise *promise)
{ {
assert(promise->set == 1); assert(promise->set == 1);
} }
+1 -1
View File
@@ -4,7 +4,7 @@
typedef struct xPromise Promise; typedef struct xPromise Promise;
Promise *Promise_New(BPAlloc *alloc, int size); Promise *Promise_New(BPAlloc *alloc, int size);
unsigned int Promise_Size(Promise *promise); unsigned int Promise_Size(Promise *promise);
void Promise_Delete(Promise *promise); void Promise_Free(Promise *promise);
void Promise_Resolve(Promise *promise, const void *data, int size); void Promise_Resolve(Promise *promise, const void *data, int size);
_Bool Promise_Subscribe(Promise *promise, void *dest); _Bool Promise_Subscribe(Promise *promise, void *dest);
_Bool Promise_Subscribe2(Promise *promise, void *dest, void *userp, void (*callback)(void*)); _Bool Promise_Subscribe2(Promise *promise, void *dest, void *userp, void (*callback)(void*));
+1 -1
View File
@@ -80,7 +80,7 @@ Source *Source_FromFile(const char *file, Error *error)
return NULL; return NULL;
} }
if(fseek(fp, 0, SEEK_END)) if(fseek(fp, 0, SEEK_SET))
{ {
Error_Report(error, 1, "Call to fseek failed (%s, errno = %d)", strerror(errno), errno); Error_Report(error, 1, "Call to fseek failed (%s, errno = %d)", strerror(errno), errno);
fclose(fp); fclose(fp);