mirror of https://gitlab.com/nakst/essence
scripting engine: add anytype
This commit is contained in:
parent
f280516530
commit
21e94baadd
158
util/script.c
158
util/script.c
|
@ -113,6 +113,8 @@
|
||||||
#define T_ERR_CAST (91)
|
#define T_ERR_CAST (91)
|
||||||
#define T_IF_ERR (92)
|
#define T_IF_ERR (92)
|
||||||
#define T_INTTYPE_CONSTANT (93)
|
#define T_INTTYPE_CONSTANT (93)
|
||||||
|
#define T_ANYTYPE_CAST (94)
|
||||||
|
#define T_CAST_TYPE_WRAPPER (95)
|
||||||
|
|
||||||
#define T_EXIT_SCOPE (100)
|
#define T_EXIT_SCOPE (100)
|
||||||
#define T_END_FUNCTION (101)
|
#define T_END_FUNCTION (101)
|
||||||
|
@ -170,6 +172,7 @@
|
||||||
#define T_OP_DEFAULT (162)
|
#define T_OP_DEFAULT (162)
|
||||||
#define T_OP_INT_TO_FLOAT (163)
|
#define T_OP_INT_TO_FLOAT (163)
|
||||||
#define T_OP_FLOAT_TRUNCATE (164)
|
#define T_OP_FLOAT_TRUNCATE (164)
|
||||||
|
#define T_OP_CAST (165)
|
||||||
|
|
||||||
#define T_IF (170)
|
#define T_IF (170)
|
||||||
#define T_WHILE (171)
|
#define T_WHILE (171)
|
||||||
|
@ -201,6 +204,7 @@
|
||||||
#define T_RETERR (197)
|
#define T_RETERR (197)
|
||||||
#define T_INTTYPE (198)
|
#define T_INTTYPE (198)
|
||||||
#define T_HANDLETYPE (199)
|
#define T_HANDLETYPE (199)
|
||||||
|
#define T_ANYTYPE (200)
|
||||||
|
|
||||||
#define STACK_READ_STRING(textVariable, bytesVariable, stackIndex) \
|
#define STACK_READ_STRING(textVariable, bytesVariable, stackIndex) \
|
||||||
if (context->c->stackPointer < stackIndex) return -1; \
|
if (context->c->stackPointer < stackIndex) return -1; \
|
||||||
|
@ -311,40 +315,45 @@ typedef struct HeapEntry {
|
||||||
bool internalValuesAreManaged;
|
bool internalValuesAreManaged;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
struct {
|
struct { // T_STR
|
||||||
// TODO Inlining small strings.
|
// TODO Inlining small strings.
|
||||||
size_t bytes;
|
size_t bytes;
|
||||||
char *text;
|
char *text;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct {
|
struct { // T_STRUCT
|
||||||
uint16_t fieldCount;
|
uint16_t fieldCount;
|
||||||
Value *fields; // Managed bools placed before this.
|
Value *fields; // Managed bools placed before this.
|
||||||
};
|
};
|
||||||
|
|
||||||
struct {
|
struct { // T_LIST
|
||||||
uint32_t length, allocated;
|
uint32_t length, allocated;
|
||||||
Value *list;
|
Value *list;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct {
|
struct { // Unused entry.
|
||||||
uintptr_t nextUnusedEntry;
|
uintptr_t nextUnusedEntry;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct {
|
struct { // Various function pointers.
|
||||||
int64_t lambdaID;
|
int64_t lambdaID;
|
||||||
Value curryValue;
|
Value curryValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct {
|
struct { // T_CONCAT
|
||||||
uint32_t concat1, concat2;
|
uint32_t concat1, concat2;
|
||||||
size_t concatBytes;
|
size_t concatBytes;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct {
|
struct { // T_ERR
|
||||||
bool success;
|
bool success;
|
||||||
Value errorValue;
|
Value errorValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct { // T_ANYTYPE
|
||||||
|
Node *anyType;
|
||||||
|
Value anyValue;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
} HeapEntry;
|
} HeapEntry;
|
||||||
|
|
||||||
|
@ -971,6 +980,7 @@ Token TokenNext(Tokenizer *tokenizer) {
|
||||||
else if KEYWORD("#option") token.type = T_OPTION;
|
else if KEYWORD("#option") token.type = T_OPTION;
|
||||||
else if KEYWORD("#persist") token.type = T_PERSIST;
|
else if KEYWORD("#persist") token.type = T_PERSIST;
|
||||||
else if KEYWORD("#success") token.type = T_SUCCESS;
|
else if KEYWORD("#success") token.type = T_SUCCESS;
|
||||||
|
else if KEYWORD("anytype") token.type = T_ANYTYPE;
|
||||||
else if KEYWORD("assert") token.type = T_ASSERT;
|
else if KEYWORD("assert") token.type = T_ASSERT;
|
||||||
else if KEYWORD("await") token.type = T_AWAIT;
|
else if KEYWORD("await") token.type = T_AWAIT;
|
||||||
else if KEYWORD("bool") token.type = T_BOOL;
|
else if KEYWORD("bool") token.type = T_BOOL;
|
||||||
|
@ -1098,6 +1108,7 @@ Node *ParseType(Tokenizer *tokenizer, bool maybe, bool allowVoid, bool allowTupl
|
||||||
|| node->token.type == T_VOID
|
|| node->token.type == T_VOID
|
||||||
|| node->token.type == T_TUPLE
|
|| node->token.type == T_TUPLE
|
||||||
|| node->token.type == T_ERR
|
|| node->token.type == T_ERR
|
||||||
|
|| node->token.type == T_ANYTYPE
|
||||||
|| node->token.type == T_IDENTIFIER) {
|
|| node->token.type == T_IDENTIFIER) {
|
||||||
node->type = node->token.type;
|
node->type = node->token.type;
|
||||||
|
|
||||||
|
@ -1432,8 +1443,38 @@ Node *ParseExpression(Tokenizer *tokenizer, bool allowAssignment, uint8_t preced
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
node = ParseCall(tokenizer, node);
|
if (operationName.textBytes == 4 && 0 == MemoryCompare(operationName.text, "cast", 4)) {
|
||||||
if (!node) return NULL;
|
Node *n = node;
|
||||||
|
node = (Node *) AllocateFixed(sizeof(Node));
|
||||||
|
node->token = TokenNext(tokenizer);
|
||||||
|
|
||||||
|
if (node->token.type == T_ERROR) {
|
||||||
|
return NULL;
|
||||||
|
} else if (node->token.type != T_LEFT_ROUND) {
|
||||||
|
PrintError2(tokenizer, node, "Expected a '(' before the type to cast to.\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->firstChild = n;
|
||||||
|
Node *type = ParseType(tokenizer, false, false, false);
|
||||||
|
if (!type) return NULL;
|
||||||
|
node->firstChild->sibling = (Node *) AllocateFixed(sizeof(Node));
|
||||||
|
node->firstChild->sibling->type = T_CAST_TYPE_WRAPPER;
|
||||||
|
node->firstChild->sibling->firstChild = type;
|
||||||
|
|
||||||
|
Token token = TokenNext(tokenizer);
|
||||||
|
|
||||||
|
if (token.type == T_ERROR) {
|
||||||
|
return NULL;
|
||||||
|
} else if (token.type != T_RIGHT_ROUND) {
|
||||||
|
PrintError2(tokenizer, node, "Expected a ')' after the type to cast to.\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
node = ParseCall(tokenizer, node);
|
||||||
|
if (!node) return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
node->type = T_COLON;
|
node->type = T_COLON;
|
||||||
node->token = operationName;
|
node->token = operationName;
|
||||||
} else if ((token.type == T_EQUALS || token.type == T_ADD || token.type == T_MINUS || token.type == T_BITWISE_XOR
|
} else if ((token.type == T_EQUALS || token.type == T_ADD || token.type == T_MINUS || token.type == T_BITWISE_XOR
|
||||||
|
@ -2625,7 +2666,7 @@ bool ASTIsIntType(Node *node) {
|
||||||
|
|
||||||
bool ASTIsManagedType(Node *node) {
|
bool ASTIsManagedType(Node *node) {
|
||||||
return node->type == T_STR || node->type == T_LIST || node->type == T_STRUCT
|
return node->type == T_STR || node->type == T_LIST || node->type == T_STRUCT
|
||||||
|| node->type == T_FUNCPTR || node->type == T_FUNCPTR || node->type == T_ERR;
|
|| node->type == T_FUNCPTR || node->type == T_FUNCPTR || node->type == T_ERR || node->type == T_ANYTYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ASTGetTypePopCount(Node *node) {
|
int ASTGetTypePopCount(Node *node) {
|
||||||
|
@ -2660,7 +2701,8 @@ bool ASTLookupTypeIdentifiers(Tokenizer *tokenizer, Node *node) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node->type == T_DECLARE || node->type == T_ARGUMENT || node->type == T_NEW || node->type == T_LIST || node->hasTypeInheritanceParent) {
|
if (node->type == T_DECLARE || node->type == T_ARGUMENT || node->type == T_NEW || node->type == T_LIST
|
||||||
|
|| node->type == T_CAST_TYPE_WRAPPER || node->hasTypeInheritanceParent) {
|
||||||
Node *type = node->firstChild;
|
Node *type = node->firstChild;
|
||||||
|
|
||||||
if (node->hasTypeInheritanceParent && type && type->type != T_IDENTIFIER) {
|
if (node->hasTypeInheritanceParent && type && type->type != T_IDENTIFIER) {
|
||||||
|
@ -2732,31 +2774,40 @@ bool ASTImplicitCastIsPossible(Node *targetType, Node *expressionType) {
|
||||||
// Only allow implicit casts to a type that inherits from this.
|
// Only allow implicit casts to a type that inherits from this.
|
||||||
Node *inherit = targetType->firstChild;
|
Node *inherit = targetType->firstChild;
|
||||||
return inherit && inherit->type != T_INTTYPE_CONSTANT && (ASTMatching(inherit, expressionType) || ASTImplicitCastIsPossible(inherit, expressionType));
|
return inherit && inherit->type != T_INTTYPE_CONSTANT && (ASTMatching(inherit, expressionType) || ASTImplicitCastIsPossible(inherit, expressionType));
|
||||||
|
} else if (targetType->type == T_ANYTYPE && expressionType->type != T_VOID) {
|
||||||
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Node *ASTImplicitCastApply(Tokenizer *tokenizer, Node *parent, Node *target, Node *expression) {
|
Node *ASTImplicitCastApply(Tokenizer *tokenizer, Node *parent, Node *target, Node *expression) {
|
||||||
|
Node *cast = NULL;
|
||||||
|
|
||||||
if (target->type == T_ERR && ASTMatching(target->firstChild, expression->expressionType)) {
|
if (target->type == T_ERR && ASTMatching(target->firstChild, expression->expressionType)) {
|
||||||
if (!expression->expressionType || ASTMatching(expression->expressionType, &globalExpressionTypeVoid)) {
|
if (!expression->expressionType || ASTMatching(expression->expressionType, &globalExpressionTypeVoid)) {
|
||||||
PrintError2(tokenizer, parent, "You cannot assign a value of 'void' to 'err[void]'.\nInstead, use the constant '#success'.\n");
|
PrintError2(tokenizer, parent, "You cannot assign a value of 'void' to 'err[void]'.\nInstead, use the constant '#success'.\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Node *cast = (Node *) AllocateFixed(sizeof(Node));
|
cast = (Node *) AllocateFixed(sizeof(Node));
|
||||||
cast->type = T_ERR_CAST;
|
cast->type = T_ERR_CAST;
|
||||||
cast->scope = parent->scope;
|
|
||||||
cast->parent = parent;
|
|
||||||
cast->firstChild = expression;
|
|
||||||
return cast;
|
|
||||||
} else if ((target->type == T_HANDLETYPE && expression->expressionType->type == T_HANDLETYPE)
|
} else if ((target->type == T_HANDLETYPE && expression->expressionType->type == T_HANDLETYPE)
|
||||||
|| (target->type == T_INTTYPE && expression->expressionType->type == T_INTTYPE)) {
|
|| (target->type == T_INTTYPE && expression->expressionType->type == T_INTTYPE)) {
|
||||||
return expression; // Nothing needs to be done to cast between handletypes or inttypes.
|
return expression; // Nothing needs to be done to cast between handletypes or inttypes.
|
||||||
|
} else if (target->type == T_ANYTYPE) {
|
||||||
|
cast = (Node *) AllocateFixed(sizeof(Node));
|
||||||
|
cast->type = T_ANYTYPE_CAST;
|
||||||
} else {
|
} else {
|
||||||
Assert(false);
|
Assert(false);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cast->scope = parent->scope;
|
||||||
|
cast->parent = parent;
|
||||||
|
cast->firstChild = expression;
|
||||||
|
cast->expressionType = target;
|
||||||
|
return cast;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value ASTNumericLiteralToValue(Node *node) {
|
Value ASTNumericLiteralToValue(Node *node) {
|
||||||
|
@ -2889,13 +2940,13 @@ bool ASTSetTypes(Tokenizer *tokenizer, Node *node) {
|
||||||
|
|
||||||
if (node->type == T_ROOT || node->type == T_BLOCK
|
if (node->type == T_ROOT || node->type == T_BLOCK
|
||||||
|| node->type == T_INT || node->type == T_FLOAT || node->type == T_STR
|
|| node->type == T_INT || node->type == T_FLOAT || node->type == T_STR
|
||||||
|| node->type == T_LIST || node->type == T_TUPLE || node->type == T_ERR
|
|| node->type == T_LIST || node->type == T_TUPLE || node->type == T_ERR || node->type == T_ANYTYPE
|
||||||
|| node->type == T_BOOL || node->type == T_VOID || node->type == T_IDENTIFIER
|
|| node->type == T_BOOL || node->type == T_VOID || node->type == T_IDENTIFIER
|
||||||
|| node->type == T_ARGUMENTS || node->type == T_ARGUMENT
|
|| node->type == T_ARGUMENTS || node->type == T_ARGUMENT
|
||||||
|| node->type == T_STRUCT || node->type == T_FUNCTYPE || node->type == T_IMPORT
|
|| node->type == T_STRUCT || node->type == T_FUNCTYPE || node->type == T_IMPORT
|
||||||
|| node->type == T_IMPORT_PATH || node->type == T_INTTYPE || node->type == T_HANDLETYPE
|
|| node->type == T_IMPORT_PATH || node->type == T_INTTYPE || node->type == T_HANDLETYPE
|
||||||
|| node->type == T_FUNCPTR || node->type == T_FUNCBODY || node->type == T_FUNCTION
|
|| node->type == T_FUNCPTR || node->type == T_FUNCBODY || node->type == T_FUNCTION
|
||||||
|| node->type == T_REPL_RESULT || node->type == T_DECLARE_GROUP) {
|
|| node->type == T_REPL_RESULT || node->type == T_DECLARE_GROUP || node->type == T_CAST_TYPE_WRAPPER) {
|
||||||
} else if (node->type == T_NUMERIC_LITERAL) {
|
} else if (node->type == T_NUMERIC_LITERAL) {
|
||||||
size_t dotCount = 0;
|
size_t dotCount = 0;
|
||||||
|
|
||||||
|
@ -3306,8 +3357,9 @@ bool ASTSetTypes(Tokenizer *tokenizer, Node *node) {
|
||||||
bool isErr = expressionType->type == T_ERR;
|
bool isErr = expressionType->type == T_ERR;
|
||||||
bool isInt = expressionType->type == T_INT;
|
bool isInt = expressionType->type == T_INT;
|
||||||
bool isFloat = expressionType->type == T_FLOAT;
|
bool isFloat = expressionType->type == T_FLOAT;
|
||||||
|
bool isAnyType = expressionType->type == T_ANYTYPE;
|
||||||
|
|
||||||
if (!isList && !isStr & !isFuncPtr && !isErr && !isInt && !isFloat) {
|
if (!isList && !isStr & !isFuncPtr && !isErr && !isInt && !isFloat && !isAnyType) {
|
||||||
PrintError2(tokenizer, node, "This type does not have any ':' operations.\n");
|
PrintError2(tokenizer, node, "This type does not have any ':' operations.\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -3405,6 +3457,13 @@ bool ASTSetTypes(Tokenizer *tokenizer, Node *node) {
|
||||||
simple = false;
|
simple = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (isAnyType && KEYWORD("cast")) {
|
||||||
|
Assert(node->firstChild->sibling->type == T_CAST_TYPE_WRAPPER);
|
||||||
|
node->expressionType = node->firstChild->sibling->firstChild;
|
||||||
|
op = T_OP_CAST;
|
||||||
|
simple = false;
|
||||||
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
PrintError2(tokenizer, node, "This type does not have an operation called '%.*s'.\n", token.textBytes, token.text);
|
PrintError2(tokenizer, node, "This type does not have an operation called '%.*s'.\n", token.textBytes, token.text);
|
||||||
return false;
|
return false;
|
||||||
|
@ -4094,15 +4153,22 @@ bool FunctionBuilderRecurse(Tokenizer *tokenizer, Node *node, FunctionBuilder *b
|
||||||
} else if (node->type == T_COLON) {
|
} else if (node->type == T_COLON) {
|
||||||
FunctionBuilderRecurse(tokenizer, node->firstChild, builder, false);
|
FunctionBuilderRecurse(tokenizer, node->firstChild, builder, false);
|
||||||
|
|
||||||
Node *argument = node->firstChild->sibling->firstChild;
|
if (node->operationType != T_OP_CAST) {
|
||||||
|
Node *argument = node->firstChild->sibling->firstChild;
|
||||||
|
|
||||||
while (argument) {
|
while (argument) {
|
||||||
FunctionBuilderRecurse(tokenizer, argument, builder, false);
|
FunctionBuilderRecurse(tokenizer, argument, builder, false);
|
||||||
argument = argument->sibling;
|
argument = argument->sibling;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionBuilderAddLineNumber(builder, node);
|
FunctionBuilderAddLineNumber(builder, node);
|
||||||
FunctionBuilderAppend(builder, &node->operationType, sizeof(node->operationType));
|
FunctionBuilderAppend(builder, &node->operationType, sizeof(node->operationType));
|
||||||
|
|
||||||
|
if (node->operationType == T_OP_CAST) {
|
||||||
|
FunctionBuilderAppend(builder, &node->expressionType, sizeof(node->expressionType));
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} else if (node->type == T_LIST_LITERAL) {
|
} else if (node->type == T_LIST_LITERAL) {
|
||||||
// Step 1: Create the list.
|
// Step 1: Create the list.
|
||||||
|
@ -4214,6 +4280,10 @@ bool FunctionBuilderRecurse(Tokenizer *tokenizer, Node *node, FunctionBuilder *b
|
||||||
} else if (node->type == T_NULL || node->type == T_LOGICAL_NOT || node->type == T_AWAIT || node->type == T_ERR_CAST) {
|
} else if (node->type == T_NULL || node->type == T_LOGICAL_NOT || node->type == T_AWAIT || node->type == T_ERR_CAST) {
|
||||||
FunctionBuilderAddLineNumber(builder, node);
|
FunctionBuilderAddLineNumber(builder, node);
|
||||||
FunctionBuilderAppend(builder, &node->type, sizeof(node->type));
|
FunctionBuilderAppend(builder, &node->type, sizeof(node->type));
|
||||||
|
} else if (node->type == T_ANYTYPE_CAST) {
|
||||||
|
FunctionBuilderAddLineNumber(builder, node);
|
||||||
|
FunctionBuilderAppend(builder, &node->type, sizeof(node->type));
|
||||||
|
FunctionBuilderAppend(builder, &node->firstChild->expressionType, sizeof(node->firstChild->expressionType));
|
||||||
} else if (node->type == T_ASSERT) {
|
} else if (node->type == T_ASSERT) {
|
||||||
FunctionBuilderAddLineNumber(builder, node);
|
FunctionBuilderAddLineNumber(builder, node);
|
||||||
|
|
||||||
|
@ -4474,6 +4544,10 @@ void HeapGarbageCollectMark(ExecutionContext *context, uintptr_t index) {
|
||||||
if (context->heap[index].internalValuesAreManaged) {
|
if (context->heap[index].internalValuesAreManaged) {
|
||||||
HeapGarbageCollectMark(context, context->heap[index].errorValue.i);
|
HeapGarbageCollectMark(context, context->heap[index].errorValue.i);
|
||||||
}
|
}
|
||||||
|
} else if (context->heap[index].type == T_ANYTYPE) {
|
||||||
|
if (context->heap[index].internalValuesAreManaged) {
|
||||||
|
HeapGarbageCollectMark(context, context->heap[index].anyValue.i);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Assert(false);
|
Assert(false);
|
||||||
}
|
}
|
||||||
|
@ -4488,7 +4562,8 @@ void HeapFreeEntry(ExecutionContext *context, uintptr_t i) {
|
||||||
AllocateResize(context->heap[i].list, 0);
|
AllocateResize(context->heap[i].list, 0);
|
||||||
} else if (context->heap[i].type == T_OP_DISCARD || context->heap[i].type == T_OP_ASSERT
|
} else if (context->heap[i].type == T_OP_DISCARD || context->heap[i].type == T_OP_ASSERT
|
||||||
|| context->heap[i].type == T_FUNCPTR || context->heap[i].type == T_OP_CURRY
|
|| context->heap[i].type == T_FUNCPTR || context->heap[i].type == T_OP_CURRY
|
||||||
|| context->heap[i].type == T_CONCAT || context->heap[i].type == T_ERR) {
|
|| context->heap[i].type == T_CONCAT || context->heap[i].type == T_ERR
|
||||||
|
|| context->heap[i].type == T_ANYTYPE) {
|
||||||
} else {
|
} else {
|
||||||
Assert(false);
|
Assert(false);
|
||||||
}
|
}
|
||||||
|
@ -5308,6 +5383,41 @@ int ScriptExecuteFunction(uintptr_t instructionPointer, ExecutionContext *contex
|
||||||
v.i = index;
|
v.i = index;
|
||||||
context->c->stackIsManaged[context->c->stackPointer - 1] = true;
|
context->c->stackIsManaged[context->c->stackPointer - 1] = true;
|
||||||
context->c->stack[context->c->stackPointer - 1] = v;
|
context->c->stack[context->c->stackPointer - 1] = v;
|
||||||
|
} else if (command == T_ANYTYPE_CAST) {
|
||||||
|
if (context->c->stackPointer < 1) return -1;
|
||||||
|
|
||||||
|
// TODO Handle memory allocation failures here.
|
||||||
|
uintptr_t index = HeapAllocate(context);
|
||||||
|
context->heap[index].type = T_ANYTYPE;
|
||||||
|
MemoryCopy(&context->heap[index].anyType, &functionData[instructionPointer], sizeof(context->heap[index].anyType));
|
||||||
|
context->heap[index].internalValuesAreManaged = ASTIsManagedType(context->heap[index].anyType);
|
||||||
|
context->heap[index].anyValue = context->c->stack[context->c->stackPointer - 1];
|
||||||
|
|
||||||
|
Value v;
|
||||||
|
v.i = index;
|
||||||
|
context->c->stackIsManaged[context->c->stackPointer - 1] = true;
|
||||||
|
context->c->stack[context->c->stackPointer - 1] = v;
|
||||||
|
|
||||||
|
instructionPointer += sizeof(context->heap[index].anyType);
|
||||||
|
} else if (command == T_OP_CAST) {
|
||||||
|
if (context->c->stackPointer < 1) return -1;
|
||||||
|
if (!context->c->stackIsManaged[context->c->stackPointer - 1]) return -1;
|
||||||
|
uintptr_t index = context->c->stack[context->c->stackPointer - 1].i;
|
||||||
|
if (context->heapEntriesAllocated <= index) return -1;
|
||||||
|
HeapEntry *entry = &context->heap[index];
|
||||||
|
if (entry->type != T_ANYTYPE) return -1;
|
||||||
|
Node *expressionType;
|
||||||
|
MemoryCopy(&expressionType, &functionData[instructionPointer], sizeof(expressionType));
|
||||||
|
|
||||||
|
if (!ASTMatching(expressionType, entry->anyType)) {
|
||||||
|
PrintError4(context, instructionPointer - 1, "Invalid cast.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert(ASTIsManagedType(expressionType) == entry->internalValuesAreManaged);
|
||||||
|
context->c->stackIsManaged[context->c->stackPointer - 1] = entry->internalValuesAreManaged;
|
||||||
|
context->c->stack[context->c->stackPointer - 1] = entry->anyValue;
|
||||||
|
instructionPointer += sizeof(expressionType);
|
||||||
} else if (command == T_OP_SUCCESS) {
|
} else if (command == T_OP_SUCCESS) {
|
||||||
if (context->c->stackPointer < 1) return -1;
|
if (context->c->stackPointer < 1) return -1;
|
||||||
if (!context->c->stackIsManaged[context->c->stackPointer - 1]) return -1;
|
if (!context->c->stackIsManaged[context->c->stackPointer - 1]) return -1;
|
||||||
|
|
Loading…
Reference in New Issue