implemented nullable type notation
This commit is contained in:
+3
-1
@@ -9,4 +9,6 @@ test
|
|||||||
|
|
||||||
vgcore.*
|
vgcore.*
|
||||||
*.gcov
|
*.gcov
|
||||||
lib*.a
|
lib*.a
|
||||||
|
|
||||||
|
*.noja
|
||||||
@@ -299,6 +299,25 @@ static int bin_error(Runtime *runtime, Object **argv, unsigned int argc, Object
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int bin_istypeof(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error)
|
||||||
|
{
|
||||||
|
UNUSED(argc);
|
||||||
|
UNUSED(rets);
|
||||||
|
UNUSED(runtime);
|
||||||
|
|
||||||
|
ASSERT(argc == 2);
|
||||||
|
|
||||||
|
bool yes = Object_IsTypeOf(argv[0], argv[1]);
|
||||||
|
|
||||||
|
Heap *heap = Runtime_GetHeap(runtime);
|
||||||
|
Object *o_yes = Object_FromBool(yes, heap, error);
|
||||||
|
if (o_yes == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
rets[0] = o_yes;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
void bins_basic_init(StaticMapSlot slots[])
|
void bins_basic_init(StaticMapSlot slots[])
|
||||||
{
|
{
|
||||||
slots[0].as_type = Object_GetTypeType();
|
slots[0].as_type = Object_GetTypeType();
|
||||||
@@ -311,6 +330,7 @@ void bins_basic_init(StaticMapSlot slots[])
|
|||||||
slots[7].as_type = Object_GetMapType();
|
slots[7].as_type = Object_GetMapType();
|
||||||
slots[8].as_type = Object_GetFileType();
|
slots[8].as_type = Object_GetFileType();
|
||||||
slots[9].as_type = Object_GetDirType();
|
slots[9].as_type = Object_GetDirType();
|
||||||
|
slots[10].as_type = Object_GetNullableType();
|
||||||
}
|
}
|
||||||
|
|
||||||
StaticMapSlot bins_basic[] = {
|
StaticMapSlot bins_basic[] = {
|
||||||
@@ -324,6 +344,7 @@ StaticMapSlot bins_basic[] = {
|
|||||||
{ TYPENAME_MAP, SM_TYPE, .as_type = NULL /* Until bins_basic_init is called */ },
|
{ TYPENAME_MAP, SM_TYPE, .as_type = NULL /* Until bins_basic_init is called */ },
|
||||||
{ TYPENAME_FILE, SM_TYPE, .as_type = NULL /* Until bins_basic_init is called */ },
|
{ 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_DIRECTORY, SM_TYPE, .as_type = NULL /* Until bins_basic_init is called */ },
|
||||||
|
{ TYPENAME_NULLABLE, SM_TYPE, .as_type = NULL },
|
||||||
|
|
||||||
{ "math", SM_SMAP, .as_smap = bins_math, },
|
{ "math", SM_SMAP, .as_smap = bins_math, },
|
||||||
{ "files", SM_SMAP, .as_smap = bins_files, },
|
{ "files", SM_SMAP, .as_smap = bins_files, },
|
||||||
@@ -331,11 +352,12 @@ StaticMapSlot bins_basic[] = {
|
|||||||
{ "string", SM_SMAP, .as_smap = bins_string, },
|
{ "string", SM_SMAP, .as_smap = bins_string, },
|
||||||
|
|
||||||
{ "import", SM_FUNCT, .as_funct = bin_import, .argc = 1, },
|
{ "import", SM_FUNCT, .as_funct = bin_import, .argc = 1, },
|
||||||
{ "type", SM_FUNCT, .as_funct = bin_type, .argc = 1 },
|
{ "type", SM_FUNCT, .as_funct = bin_type, .argc = 1 },
|
||||||
{ "print", SM_FUNCT, .as_funct = bin_print, .argc = -1 },
|
{ "print", SM_FUNCT, .as_funct = bin_print, .argc = -1 },
|
||||||
{ "input", SM_FUNCT, .as_funct = bin_input, .argc = 0 },
|
{ "input", SM_FUNCT, .as_funct = bin_input, .argc = 0 },
|
||||||
{ "count", SM_FUNCT, .as_funct = bin_count, .argc = 1 },
|
{ "count", SM_FUNCT, .as_funct = bin_count, .argc = 1 },
|
||||||
{ "error", SM_FUNCT, .as_funct = bin_error, .argc = 1 },
|
{ "error", SM_FUNCT, .as_funct = bin_error, .argc = 1 },
|
||||||
{ "assert", SM_FUNCT, .as_funct = bin_assert, .argc = -1 },
|
{ "assert", SM_FUNCT, .as_funct = bin_assert, .argc = -1 },
|
||||||
|
{ "istypeof", SM_FUNCT, .as_funct = bin_istypeof, .argc = 2, },
|
||||||
{ NULL, SM_END, {}, {} },
|
{ NULL, SM_END, {}, {} },
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,4 +12,6 @@
|
|||||||
#define TYPENAME_BUFFER "Buffer"
|
#define TYPENAME_BUFFER "Buffer"
|
||||||
|
|
||||||
#define TYPENAME_FILE "File"
|
#define TYPENAME_FILE "File"
|
||||||
#define TYPENAME_DIRECTORY "Directory"
|
#define TYPENAME_DIRECTORY "Directory"
|
||||||
|
|
||||||
|
#define TYPENAME_NULLABLE "NullableType"
|
||||||
@@ -82,6 +82,7 @@ static const InstrInfo instr_table[] = {
|
|||||||
[OPCODE_GRT] = {"GRT", 0, NULL},
|
[OPCODE_GRT] = {"GRT", 0, NULL},
|
||||||
[OPCODE_LEQ] = {"LEQ", 0, NULL},
|
[OPCODE_LEQ] = {"LEQ", 0, NULL},
|
||||||
[OPCODE_GEQ] = {"GEQ", 0, NULL},
|
[OPCODE_GEQ] = {"GEQ", 0, NULL},
|
||||||
|
[OPCODE_NLB] = {"NLB", 0, NULL},
|
||||||
[OPCODE_ASS] = {"ASS", 1, (OperandType[]) {OPTP_STRING}},
|
[OPCODE_ASS] = {"ASS", 1, (OperandType[]) {OPTP_STRING}},
|
||||||
[OPCODE_POP] = {"POP", 1, (OperandType[]) {OPTP_INT}},
|
[OPCODE_POP] = {"POP", 1, (OperandType[]) {OPTP_INT}},
|
||||||
[OPCODE_CALL] = {"CALL", 2, (OperandType[]) {OPTP_INT, OPTP_INT}},
|
[OPCODE_CALL] = {"CALL", 2, (OperandType[]) {OPTP_INT, OPTP_INT}},
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ typedef enum {
|
|||||||
OPCODE_GRT,
|
OPCODE_GRT,
|
||||||
OPCODE_LEQ,
|
OPCODE_LEQ,
|
||||||
OPCODE_GEQ,
|
OPCODE_GEQ,
|
||||||
|
OPCODE_NLB,
|
||||||
OPCODE_ASS,
|
OPCODE_ASS,
|
||||||
OPCODE_POP,
|
OPCODE_POP,
|
||||||
OPCODE_CALL,
|
OPCODE_CALL,
|
||||||
|
|||||||
@@ -77,6 +77,9 @@ typedef enum {
|
|||||||
EXPR_STRING,
|
EXPR_STRING,
|
||||||
EXPR_IDENT,
|
EXPR_IDENT,
|
||||||
EXPR_SELECT,
|
EXPR_SELECT,
|
||||||
|
|
||||||
|
EXPR_NULLABLETYPE,
|
||||||
|
EXPR_SUMTYPE,
|
||||||
} ExprKind;
|
} ExprKind;
|
||||||
|
|
||||||
typedef struct Node Node;
|
typedef struct Node Node;
|
||||||
|
|||||||
@@ -174,6 +174,7 @@ static Opcode exprkind_to_opcode(ExprKind kind)
|
|||||||
{
|
{
|
||||||
switch(kind)
|
switch(kind)
|
||||||
{
|
{
|
||||||
|
case EXPR_NULLABLETYPE: return OPCODE_NLB;
|
||||||
case EXPR_NOT: return OPCODE_NOT;
|
case EXPR_NOT: return OPCODE_NOT;
|
||||||
case EXPR_POS: return OPCODE_POS;
|
case EXPR_POS: return OPCODE_POS;
|
||||||
case EXPR_NEG: return OPCODE_NEG;
|
case EXPR_NEG: return OPCODE_NEG;
|
||||||
@@ -475,10 +476,13 @@ static void emitInstrForExprNode(CodegenContext *ctx, ExprNode *expr,
|
|||||||
switch(expr->kind)
|
switch(expr->kind)
|
||||||
{
|
{
|
||||||
case EXPR_PAIR:
|
case EXPR_PAIR:
|
||||||
CodegenContext_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.
|
||||||
|
|
||||||
|
case EXPR_NULLABLETYPE:
|
||||||
case EXPR_NOT:
|
case EXPR_NOT:
|
||||||
case EXPR_POS: case EXPR_NEG:
|
case EXPR_POS: case EXPR_NEG:
|
||||||
case EXPR_ADD: case EXPR_SUB:
|
case EXPR_ADD: case EXPR_SUB:
|
||||||
|
|||||||
@@ -63,6 +63,7 @@
|
|||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|
||||||
|
TOPT = '?',
|
||||||
TPOS = '+',
|
TPOS = '+',
|
||||||
TNEG = '-',
|
TNEG = '-',
|
||||||
|
|
||||||
@@ -556,6 +557,7 @@ static Node *parse_statement(Context *ctx)
|
|||||||
case '[':
|
case '[':
|
||||||
case '+':
|
case '+':
|
||||||
case '-':
|
case '-':
|
||||||
|
case '?':
|
||||||
case TINT:
|
case TINT:
|
||||||
case TFLOAT:
|
case TFLOAT:
|
||||||
case TSTRING:
|
case TSTRING:
|
||||||
@@ -1544,6 +1546,7 @@ static Node *parse_prefix_expression(Context *ctx)
|
|||||||
|
|
||||||
case '+':
|
case '+':
|
||||||
case '-':
|
case '-':
|
||||||
|
case '?':
|
||||||
case TKWNOT:
|
case TKWNOT:
|
||||||
{
|
{
|
||||||
Token *unary_operator = current_token(ctx);
|
Token *unary_operator = current_token(ctx);
|
||||||
@@ -1569,6 +1572,7 @@ static Node *parse_prefix_expression(Context *ctx)
|
|||||||
|
|
||||||
switch(unary_operator->kind)
|
switch(unary_operator->kind)
|
||||||
{
|
{
|
||||||
|
case '?': temp->base.kind = EXPR_NULLABLETYPE; break;
|
||||||
case '+': temp->base.kind = EXPR_POS; break;
|
case '+': temp->base.kind = EXPR_POS; break;
|
||||||
case '-': temp->base.kind = EXPR_NEG; break;
|
case '-': temp->base.kind = EXPR_NEG; break;
|
||||||
case TKWNOT: temp->base.kind = EXPR_NOT; break;
|
case TKWNOT: temp->base.kind = EXPR_NOT; break;
|
||||||
@@ -2217,4 +2221,4 @@ static Node *parse_dowhile_statement(Context *ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (Node*) dowhl;
|
return (Node*) dowhl;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
#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);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Object base;
|
||||||
|
Object *item;
|
||||||
|
} NullableObject;
|
||||||
|
|
||||||
|
static TypeObject t_nullable = {
|
||||||
|
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
||||||
|
.name = TYPENAME_NULLABLE,
|
||||||
|
.size = sizeof(NullableObject),
|
||||||
|
.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_GetNullableType()
|
||||||
|
{
|
||||||
|
return &t_nullable;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object *Object_NewNullable(Object *item, Heap *heap, Error *error)
|
||||||
|
{
|
||||||
|
NullableObject *nullable = (NullableObject*) Heap_Malloc(heap, &t_nullable, error);
|
||||||
|
if (nullable != NULL)
|
||||||
|
nullable->item = item;
|
||||||
|
return (Object*) nullable;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
istypeof(Object *self,
|
||||||
|
Object *other)
|
||||||
|
{
|
||||||
|
NullableObject *nullable = (NullableObject*) self;
|
||||||
|
if (Object_IsNone(other))
|
||||||
|
return true;
|
||||||
|
return Object_IsTypeOf(nullable->item, other);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void walk(Object *self, void (*callback)(Object **referer, void *userp), void *userp)
|
||||||
|
{
|
||||||
|
NullableObject *nullable = (NullableObject*) self;
|
||||||
|
callback(&nullable->item, userp);
|
||||||
|
}
|
||||||
@@ -33,14 +33,21 @@
|
|||||||
#include "../common/defs.h"
|
#include "../common/defs.h"
|
||||||
|
|
||||||
static _Bool op_eql(Object *self, Object *other);
|
static _Bool op_eql(Object *self, Object *other);
|
||||||
|
static bool istypeof(Object *self, Object *other);
|
||||||
|
|
||||||
TypeObject t_type = {
|
TypeObject t_type = {
|
||||||
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
||||||
.name = TYPENAME_TYPE,
|
.name = TYPENAME_TYPE,
|
||||||
.size = sizeof(TypeObject),
|
.size = sizeof(TypeObject),
|
||||||
|
.istypeof = istypeof,
|
||||||
.op_eql = op_eql,
|
.op_eql = op_eql,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bool istypeof(Object *self, Object *other)
|
||||||
|
{
|
||||||
|
return other->type == (TypeObject*) self;
|
||||||
|
}
|
||||||
|
|
||||||
TypeObject *Object_GetTypeType()
|
TypeObject *Object_GetTypeType()
|
||||||
{
|
{
|
||||||
return &t_type;
|
return &t_type;
|
||||||
@@ -71,6 +78,13 @@ const TypeObject *Object_GetType(const Object *obj)
|
|||||||
return obj->type;
|
return obj->type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Object_IsTypeOf(Object *typ, Object *obj)
|
||||||
|
{
|
||||||
|
if (typ->type->istypeof == NULL)
|
||||||
|
return false;
|
||||||
|
return typ->type->istypeof(typ, obj);
|
||||||
|
}
|
||||||
|
|
||||||
int Object_Hash(Object *obj)
|
int Object_Hash(Object *obj)
|
||||||
{
|
{
|
||||||
ASSERT(obj != NULL);
|
ASSERT(obj != NULL);
|
||||||
|
|||||||
@@ -72,6 +72,9 @@ struct TypeObject {
|
|||||||
bool (*insert)(Object *self, Object *key, Object *val, Heap *heap, Error *err);
|
bool (*insert)(Object *self, Object *key, Object *val, Heap *heap, Error *err);
|
||||||
int (*count)(Object *self);
|
int (*count)(Object *self);
|
||||||
|
|
||||||
|
// Types.
|
||||||
|
bool (*istypeof)(Object *self, Object *other);
|
||||||
|
|
||||||
bool (*op_eql)(Object *self, Object *other);
|
bool (*op_eql)(Object *self, Object *other);
|
||||||
void (*walk) (Object *self, void (*callback)(Object **referer, void *userp), void *userp);
|
void (*walk) (Object *self, void (*callback)(Object **referer, void *userp), void *userp);
|
||||||
void (*walkexts)(Object *self, void (*callback)(void **referer, unsigned int size, void *userp), void *userp);
|
void (*walkexts)(Object *self, void (*callback)(void **referer, unsigned int size, void *userp), void *userp);
|
||||||
@@ -100,6 +103,7 @@ int Object_Hash (Object *obj);
|
|||||||
Object* Object_Copy (Object *obj, Heap *heap, Error *err);
|
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);
|
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);
|
void Object_Print(Object *obj, FILE *fp);
|
||||||
|
bool Object_IsTypeOf(Object *typ, Object *obj);
|
||||||
Object* Object_Select(Object *coll, Object *key, Heap *heap, Error *err);
|
Object* Object_Select(Object *coll, Object *key, Heap *heap, Error *err);
|
||||||
Object* Object_Delete(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);
|
bool Object_Insert(Object *coll, Object *key, Object *val, Heap *heap, Error *err);
|
||||||
@@ -114,6 +118,7 @@ Object* Object_NewNone(Heap *heap, Error *error);
|
|||||||
Object* Object_NewBuffer(size_t size, Heap *heap, Error *error);
|
Object* Object_NewBuffer(size_t size, Heap *heap, Error *error);
|
||||||
Object* Object_NewClosure(Object *parent, Object *new_map, 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_SliceBuffer(Object *obj, size_t offset, size_t length, Heap *heap, Error *error);
|
||||||
|
Object* Object_NewNullable(Object *item, 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_FromBool (bool val, Heap *heap, Error *error);
|
||||||
@@ -133,6 +138,7 @@ TypeObject *Object_GetMapType();
|
|||||||
TypeObject *Object_GetBufferType();
|
TypeObject *Object_GetBufferType();
|
||||||
TypeObject *Object_GetFileType();
|
TypeObject *Object_GetFileType();
|
||||||
TypeObject *Object_GetDirType();
|
TypeObject *Object_GetDirType();
|
||||||
|
TypeObject *Object_GetNullableType();
|
||||||
|
|
||||||
bool Object_IsNone(Object *obj);
|
bool Object_IsNone(Object *obj);
|
||||||
bool Object_IsInt(Object *obj);
|
bool Object_IsInt(Object *obj);
|
||||||
|
|||||||
@@ -653,6 +653,32 @@ static _Bool step(Runtime *runtime, Error *error)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case OPCODE_NLB:
|
||||||
|
{
|
||||||
|
ASSERT(opc == 0);
|
||||||
|
|
||||||
|
if(runtime->frame->used == 0)
|
||||||
|
{
|
||||||
|
Error_Report(error, 1, "Frame doesn't have enough items on the stack to execute NLB");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object *top = Stack_Top(runtime->stack, 0);
|
||||||
|
|
||||||
|
if(!Runtime_Pop(runtime, error, 1))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ASSERT(top != NULL);
|
||||||
|
|
||||||
|
Object *nullable = Object_NewNullable(top, runtime->heap, error);
|
||||||
|
if(nullable == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if(!Runtime_Push(runtime, error, nullable))
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
case OPCODE_ADD:
|
case OPCODE_ADD:
|
||||||
case OPCODE_SUB:
|
case OPCODE_SUB:
|
||||||
case OPCODE_MUL:
|
case OPCODE_MUL:
|
||||||
|
|||||||
Reference in New Issue
Block a user