From ea428fdca22d5dc363836a42824c3ae1ee0b3a5b Mon Sep 17 00:00:00 2001 From: cozis Date: Mon, 5 Dec 2022 11:36:19 +0100 Subject: [PATCH] added sum types --- src/lib/builtins/basic.c | 7 ++-- src/lib/common/defs.h | 3 +- src/lib/common/executable.c | 1 + src/lib/common/executable.h | 1 + src/lib/compiler/codegen.c | 2 ++ src/lib/compiler/parse.c | 25 +++++++++----- src/lib/objects/o_list.c | 30 ++++++++++++++++ src/lib/objects/o_map.c | 27 +++++++++++++++ src/lib/objects/o_nullable.c | 10 +++--- src/lib/objects/o_sum.c | 66 ++++++++++++++++++++++++++++++++++++ src/lib/objects/objects.c | 25 +++++++++++--- src/lib/objects/objects.h | 8 +++-- src/lib/runtime/runtime.c | 26 +++++++++++++- 13 files changed, 206 insertions(+), 25 deletions(-) create mode 100644 src/lib/objects/o_sum.c diff --git a/src/lib/builtins/basic.c b/src/lib/builtins/basic.c index a9259fe..dae12d7 100644 --- a/src/lib/builtins/basic.c +++ b/src/lib/builtins/basic.c @@ -306,10 +306,9 @@ static int bin_istypeof(Runtime *runtime, Object **argv, unsigned int argc, Obje UNUSED(runtime); ASSERT(argc == 2); - - bool yes = Object_IsTypeOf(argv[0], argv[1]); - + Heap *heap = Runtime_GetHeap(runtime); + bool yes = Object_IsTypeOf(argv[0], argv[1], heap, error); Object *o_yes = Object_FromBool(yes, heap, error); if (o_yes == NULL) return -1; @@ -331,6 +330,7 @@ void bins_basic_init(StaticMapSlot slots[]) slots[8].as_type = Object_GetFileType(); slots[9].as_type = Object_GetDirType(); slots[10].as_type = Object_GetNullableType(); + slots[11].as_type = Object_GetSumType(); } StaticMapSlot bins_basic[] = { @@ -345,6 +345,7 @@ StaticMapSlot bins_basic[] = { { TYPENAME_FILE, SM_TYPE, .as_type = NULL /* Until bins_basic_init is called */ }, { TYPENAME_DIRECTORY, SM_TYPE, .as_type = NULL /* Until bins_basic_init is called */ }, { TYPENAME_NULLABLE, SM_TYPE, .as_type = NULL }, + { TYPENAME_SUM, SM_TYPE, .as_type = NULL }, { "math", SM_SMAP, .as_smap = bins_math, }, { "files", SM_SMAP, .as_smap = bins_files, }, diff --git a/src/lib/common/defs.h b/src/lib/common/defs.h index 1af4e87..d8407cb 100644 --- a/src/lib/common/defs.h +++ b/src/lib/common/defs.h @@ -14,4 +14,5 @@ #define TYPENAME_FILE "File" #define TYPENAME_DIRECTORY "Directory" -#define TYPENAME_NULLABLE "NullableType" \ No newline at end of file +#define TYPENAME_NULLABLE "NullableType" +#define TYPENAME_SUM "SumType" \ No newline at end of file diff --git a/src/lib/common/executable.c b/src/lib/common/executable.c index 397945b..830d8f7 100644 --- a/src/lib/common/executable.c +++ b/src/lib/common/executable.c @@ -83,6 +83,7 @@ static const InstrInfo instr_table[] = { [OPCODE_LEQ] = {"LEQ", 0, NULL}, [OPCODE_GEQ] = {"GEQ", 0, NULL}, [OPCODE_NLB] = {"NLB", 0, NULL}, + [OPCODE_STP] = {"STP", 0, NULL}, [OPCODE_ASS] = {"ASS", 1, (OperandType[]) {OPTP_STRING}}, [OPCODE_POP] = {"POP", 1, (OperandType[]) {OPTP_INT}}, [OPCODE_CALL] = {"CALL", 2, (OperandType[]) {OPTP_INT, OPTP_INT}}, diff --git a/src/lib/common/executable.h b/src/lib/common/executable.h index 3b79738..2fe24e2 100644 --- a/src/lib/common/executable.h +++ b/src/lib/common/executable.h @@ -68,6 +68,7 @@ typedef enum { OPCODE_LEQ, OPCODE_GEQ, OPCODE_NLB, + OPCODE_STP, OPCODE_ASS, OPCODE_POP, OPCODE_CALL, diff --git a/src/lib/compiler/codegen.c b/src/lib/compiler/codegen.c index e4885c6..240c39e 100644 --- a/src/lib/compiler/codegen.c +++ b/src/lib/compiler/codegen.c @@ -175,6 +175,7 @@ static Opcode exprkind_to_opcode(ExprKind kind) switch(kind) { case EXPR_NULLABLETYPE: return OPCODE_NLB; + case EXPR_SUMTYPE: return OPCODE_STP; case EXPR_NOT: return OPCODE_NOT; case EXPR_POS: return OPCODE_POS; case EXPR_NEG: return OPCODE_NEG; @@ -483,6 +484,7 @@ static void emitInstrForExprNode(CodegenContext *ctx, ExprNode *expr, return; // For the compiler warning. case EXPR_NULLABLETYPE: + case EXPR_SUMTYPE: case EXPR_NOT: case EXPR_POS: case EXPR_NEG: case EXPR_ADD: case EXPR_SUB: diff --git a/src/lib/compiler/parse.c b/src/lib/compiler/parse.c index 0456b33..6a2d623 100644 --- a/src/lib/compiler/parse.c +++ b/src/lib/compiler/parse.c @@ -76,6 +76,7 @@ typedef enum { TGRT = '>', TASS = '=', + TSMT = '|', TLBRK = '(', TRBRK = ')', @@ -144,7 +145,7 @@ static inline _Bool isoper(char c) c == '*' || c == '/' || c == '<' || c == '>' || c == '!' || c == '=' || - c == ','; + c == ',' || c == '|'; } /* Symbol: tokenize @@ -326,6 +327,7 @@ static Token *tokenize(Source *src, BPAlloc *alloc, Error *error) { TGEQ, 2, ">=" }, { TASS, 1, "=" }, { TCOMMA, 1, "," }, + { TSMT, 1, "|" }, }; _Bool found = 0; @@ -1600,7 +1602,8 @@ static inline _Bool isbinop(Token *tok) tok->kind == TLEQ || tok->kind == TGEQ || tok->kind == TEQL || tok->kind == TNQL || tok->kind == TKWAND || tok->kind == TKWOR || - tok->kind == '=' || tok->kind == ','; + tok->kind == '=' || tok->kind == ',' || + tok->kind == '|'; } static inline _Bool isrightassoc(Token *tok) @@ -1619,31 +1622,34 @@ static inline int precedenceof(Token *tok) case '=': return 0; - case TKWOR: + case '|': return 1; - case TKWAND: + case TKWOR: return 2; + case TKWAND: + return 3; + case '<': case '>': case TLEQ: case TGEQ: case TEQL: case TNQL: - return 3; + return 4; case '+': case '-': - return 4; + return 5; case '*': case '/': - return 5; - - case ',': return 6; + case ',': + return 7; + default: return -100000000; } @@ -1710,6 +1716,7 @@ static Node *parse_expression_2(Context *ctx, Node *left_expr, int min_prec, _Bo case TKWAND: temp->base.kind = EXPR_AND; break; case TKWOR: temp->base.kind = EXPR_OR; break; case '=': temp->base.kind = EXPR_ASS; break; + case '|': temp->base.kind = EXPR_SUMTYPE; break; case ',': temp->base.kind = EXPR_PAIR; break; default: diff --git a/src/lib/objects/o_list.c b/src/lib/objects/o_list.c index 24684c1..f0d4ef8 100644 --- a/src/lib/objects/o_list.c +++ b/src/lib/objects/o_list.c @@ -47,6 +47,7 @@ static void walk(Object *self, void (*callback)(Object **referer, void *userp static void walkexts(Object *self, void (*callback)(void **referer, unsigned int size, void *userp), void *userp); static Object *copy(Object *self, Heap *heap, Error *err); static int hash(Object *self); +static bool istypeof(Object *self, Object *other, Heap *heap, Error *error); static TypeObject t_list = { .base = (Object) { .type = &t_type, .flags = Object_STATIC }, @@ -58,10 +59,39 @@ static TypeObject t_list = { .insert = insert, .count = count, .print = print, + .istypeof = istypeof, .walk = walk, .walkexts = walkexts, }; +static bool +istypeof(Object *self, + Object *other, + Heap *heap, + Error *error) +{ + ListObject *list = (ListObject*) self; + if (!Object_IsList(other)) + return false; + + for (int i = 0; i < list->count; i++) { + + Object *key = Object_FromInt(i, heap, error); + if (key == NULL) + return false; + + Object *val = list->vals[i]; + + Object *val2 = Object_Select(other, key, heap, error); + if (val2 == NULL) + return false; + + if (!Object_IsTypeOf(val, val2, heap, error)) + return false; + } + return true; +} + static int hash(Object *self) { ASSERT(self != NULL); diff --git a/src/lib/objects/o_map.c b/src/lib/objects/o_map.c index b0c8a71..9cd8d8c 100644 --- a/src/lib/objects/o_map.c +++ b/src/lib/objects/o_map.c @@ -48,6 +48,7 @@ static void walk(Object *self, void (*callback)(Object **referer, void *userp), static void walkexts(Object *self, void (*callback)(void **referer, unsigned int size, void *userp), void *userp); static Object *copy(Object *self, Heap *heap, Error *err); static int hash(Object *self); +static bool istypeof(Object *self, Object *other, Heap *heap, Error *error); static TypeObject t_map = { .base = (Object) { .type = &t_type, .flags = Object_STATIC }, @@ -59,10 +60,36 @@ static TypeObject t_map = { .insert = insert, .count = count, .print = print, + .istypeof = istypeof, .walk = walk, .walkexts = walkexts, }; +static bool +istypeof(Object *self, + Object *other, + Heap *heap, + Error *error) +{ + MapObject *map = (MapObject*) self; + if (!Object_IsMap(other)) + return false; + + for (int i = 0; i < map->count; i++) { + + Object *key = map->keys[i]; + Object *val = map->vals[i]; + + Object *val2 = Object_Select(other, key, heap, error); + if (val2 == NULL) + return false; + + if (!Object_IsTypeOf(val, val2, heap, error)) + return false; + } + return true; +} + static inline int calc_capacity(int mapper_size) { return mapper_size * 2.0 / 3.0; diff --git a/src/lib/objects/o_nullable.c b/src/lib/objects/o_nullable.c index b7715a8..1bd6853 100644 --- a/src/lib/objects/o_nullable.c +++ b/src/lib/objects/o_nullable.c @@ -2,7 +2,7 @@ #include "objects.h" static void walk(Object *self, void (*callback)(Object **referer, void *userp), void *userp); -static bool istypeof(Object *self, Object *other); +static bool istypeof(Object *self, Object *other, Heap *heap, Error *error); typedef struct { Object base; @@ -47,16 +47,18 @@ Object *Object_NewNullable(Object *item, Heap *heap, Error *error) static bool istypeof(Object *self, - Object *other) + Object *other, + Heap *heap, + Error *error) { NullableObject *nullable = (NullableObject*) self; if (Object_IsNone(other)) return true; - return Object_IsTypeOf(nullable->item, other); + return Object_IsTypeOf(nullable->item, other, heap, error); } static void walk(Object *self, void (*callback)(Object **referer, void *userp), void *userp) { NullableObject *nullable = (NullableObject*) self; callback(&nullable->item, userp); -} \ No newline at end of file +} diff --git a/src/lib/objects/o_sum.c b/src/lib/objects/o_sum.c new file mode 100644 index 0000000..cca70d6 --- /dev/null +++ b/src/lib/objects/o_sum.c @@ -0,0 +1,66 @@ +#include "../common/defs.h" +#include "objects.h" + +static void walk(Object *self, void (*callback)(Object **referer, void *userp), void *userp); +static bool istypeof(Object *self, Object *other, Heap *heap, Error *error); + +typedef struct { + Object base; + Object *items[2]; +} SumObject; + +static TypeObject t_sum = { + .base = (Object) { .type = &t_type, .flags = Object_STATIC }, + .name = TYPENAME_SUM, + .size = sizeof(SumObject), + .init = NULL, + .free = NULL, + .hash = NULL, + .copy = NULL, + .call = NULL, + .print = NULL, + + .select = NULL, + .delete = NULL, + .insert = NULL, + .count = NULL, + + .istypeof = istypeof, + + .op_eql = NULL, + .walk = walk, + .walkexts = NULL, +}; + +TypeObject *Object_GetSumType() +{ + return &t_sum; +} + +Object *Object_NewSum(Object *item0, Object *item1, Heap *heap, Error *error) +{ + SumObject *sum = (SumObject*) Heap_Malloc(heap, &t_sum, error); + if (sum != NULL) { + sum->items[0] = item0; + sum->items[1] = item1; + } + return (Object*) sum; +} + +static bool +istypeof(Object *self, + Object *other, + Heap *heap, + Error *error) +{ + SumObject *sum = (SumObject*) self; + return Object_IsTypeOf(sum->items[0], other, heap, error) + || Object_IsTypeOf(sum->items[1], other, heap, error); +} + +static void walk(Object *self, void (*callback)(Object **referer, void *userp), void *userp) +{ + SumObject *sum = (SumObject*) self; + callback(sum->items + 0, userp); + callback(sum->items + 1, userp); +} diff --git a/src/lib/objects/objects.c b/src/lib/objects/objects.c index 189593d..958c73b 100644 --- a/src/lib/objects/objects.c +++ b/src/lib/objects/objects.c @@ -33,7 +33,7 @@ #include "../common/defs.h" static _Bool op_eql(Object *self, Object *other); -static bool istypeof(Object *self, Object *other); +static bool istypeof(Object *self, Object *other, Heap *heap, Error *error); TypeObject t_type = { .base = (Object) { .type = &t_type, .flags = Object_STATIC }, @@ -43,8 +43,10 @@ TypeObject t_type = { .op_eql = op_eql, }; -static bool istypeof(Object *self, Object *other) +static bool istypeof(Object *self, Object *other, Heap *heap, Error *error) { + UNUSED(heap); + UNUSED(error); return other->type == (TypeObject*) self; } @@ -78,11 +80,14 @@ const TypeObject *Object_GetType(const Object *obj) return obj->type; } -bool Object_IsTypeOf(Object *typ, Object *obj) +bool Object_IsTypeOf(Object *typ, + Object *obj, + Heap *heap, + Error *error) { if (typ->type->istypeof == NULL) return false; - return typ->type->istypeof(typ, obj); + return typ->type->istypeof(typ, obj, heap, error); } int Object_Hash(Object *obj) @@ -230,6 +235,16 @@ _Bool Object_IsString(Object *obj) return Object_GetType(obj) == Object_GetStringType(); } +bool Object_IsMap(Object *obj) +{ + return Object_GetType(obj) == Object_GetMapType(); +} + +bool Object_IsList(Object *obj) +{ + return Object_GetType(obj) == Object_GetListType(); +} + _Bool Object_Compare(Object *obj1, Object *obj2, Error *error) { ASSERT(obj1 != NULL); @@ -260,4 +275,4 @@ void Object_WalkExtensions(Object *parent, void (*callback)(void **referer, unsi ASSERT(parent != NULL); if(parent->type->walkexts != NULL) parent->type->walkexts(parent, callback, userp); -} \ No newline at end of file +} diff --git a/src/lib/objects/objects.h b/src/lib/objects/objects.h index b3f8d42..1012841 100644 --- a/src/lib/objects/objects.h +++ b/src/lib/objects/objects.h @@ -73,7 +73,7 @@ struct TypeObject { int (*count)(Object *self); // Types. - bool (*istypeof)(Object *self, Object *other); + bool (*istypeof)(Object *self, Object *other, Heap *heap, Error *error); bool (*op_eql)(Object *self, Object *other); void (*walk) (Object *self, void (*callback)(Object **referer, void *userp), void *userp); @@ -103,7 +103,7 @@ int Object_Hash (Object *obj); Object* Object_Copy (Object *obj, Heap *heap, Error *err); int Object_Call (Object *obj, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Heap *heap, Error *err); void Object_Print(Object *obj, FILE *fp); -bool Object_IsTypeOf(Object *typ, Object *obj); +bool Object_IsTypeOf(Object *typ, Object *obj, Heap *heap, Error *error); Object* Object_Select(Object *coll, Object *key, Heap *heap, Error *err); Object* Object_Delete(Object *coll, Object *key, Heap *heap, Error *err); bool Object_Insert(Object *coll, Object *key, Object *val, Heap *heap, Error *err); @@ -119,6 +119,7 @@ Object* Object_NewBuffer(size_t size, Heap *heap, Error *error); Object* Object_NewClosure(Object *parent, Object *new_map, Heap *heap, Error *error); Object* Object_SliceBuffer(Object *obj, size_t offset, size_t length, Heap *heap, Error *error); Object* Object_NewNullable(Object *item, Heap *heap, Error *error); +Object* Object_NewSum(Object *item0, Object *item1, Heap *heap, Error *error); Object* Object_FromInt (long long int val, Heap *heap, Error *error); Object* Object_FromBool (bool val, Heap *heap, Error *error); @@ -139,6 +140,7 @@ TypeObject *Object_GetBufferType(); TypeObject *Object_GetFileType(); TypeObject *Object_GetDirType(); TypeObject *Object_GetNullableType(); +TypeObject *Object_GetSumType(); bool Object_IsNone(Object *obj); bool Object_IsInt(Object *obj); @@ -148,6 +150,8 @@ bool Object_IsString(Object *obj); bool Object_IsBuffer(Object *obj); bool Object_IsFile(Object *obj); bool Object_IsDir(Object *obj); +bool Object_IsMap(Object *obj); +bool Object_IsList(Object *obj); long long int Object_GetInt (Object *obj); bool Object_GetBool (Object *obj); diff --git a/src/lib/runtime/runtime.c b/src/lib/runtime/runtime.c index 60f208b..4257e78 100644 --- a/src/lib/runtime/runtime.c +++ b/src/lib/runtime/runtime.c @@ -667,7 +667,7 @@ static _Bool step(Runtime *runtime, Error *error) if(!Runtime_Pop(runtime, error, 1)) return 0; - + ASSERT(top != NULL); Object *nullable = Object_NewNullable(top, runtime->heap, error); @@ -679,6 +679,30 @@ static _Bool step(Runtime *runtime, Error *error) return 1; } + case OPCODE_STP: + { + ASSERT(opc == 0); + + Object *rop = Stack_Top(runtime->stack, 0); + Object *lop = Stack_Top(runtime->stack, -1); + + if(!Runtime_Pop(runtime, error, 2)) + return 0; + + // We managed to pop rop and lop, + // so we know they're not NULL. + ASSERT(rop != NULL); + ASSERT(lop != NULL); + + Object *res = Object_NewSum(lop, rop, runtime->heap, error); + if(res == NULL) + return 0; + + if(!Runtime_Push(runtime, error, res)) + return 0; + return 1; + } + case OPCODE_ADD: case OPCODE_SUB: case OPCODE_MUL: