scripting engine: inheritance of inttypes

This commit is contained in:
nakst 2022-03-07 17:49:29 +00:00
parent d64d3ce44e
commit f280516530
1 changed files with 44 additions and 16 deletions

View File

@ -4,7 +4,8 @@
// - Other operators: remainder, ternary. // - Other operators: remainder, ternary.
// - Named optional arguments with default values. // - Named optional arguments with default values.
// - Accessing structs and functypes from imported modules. // - Accessing structs and functypes from imported modules.
// - inttype and struct inheritance. // - struct inheritance.
// - Allow implicit casts when passing functions parameters
// TODO Larger missing features: // TODO Larger missing features:
// - Serialization. // - Serialization.
@ -257,7 +258,7 @@ typedef struct Scope {
typedef struct Node { typedef struct Node {
uint8_t type; uint8_t type;
bool referencesRootScope, isExternalCall, isPersistentVariable, isOptionVariable, cycleCheck; bool referencesRootScope, isExternalCall, isPersistentVariable, isOptionVariable, cycleCheck, hasTypeInheritanceParent;
uint8_t operationType; uint8_t operationType;
int32_t inlineImportVariableIndex; int32_t inlineImportVariableIndex;
Token token; Token token;
@ -2118,6 +2119,7 @@ Node *ParseRoot(Tokenizer *tokenizer) {
node->firstChild = ParseType(tokenizer, false, false, false); node->firstChild = ParseType(tokenizer, false, false, false);
if (!node->firstChild) return NULL; if (!node->firstChild) return NULL;
semicolon = TokenNext(tokenizer); semicolon = TokenNext(tokenizer);
node->hasTypeInheritanceParent = true;
} }
if (semicolon.type != T_SEMICOLON) { if (semicolon.type != T_SEMICOLON) {
@ -2131,19 +2133,33 @@ Node *ParseRoot(Tokenizer *tokenizer) {
node->token = TokenNext(tokenizer); node->token = TokenNext(tokenizer);
*link = node; *link = node;
link = &node->sibling; link = &node->sibling;
Node **contentLink = &node->firstChild;
if (node->token.type != T_IDENTIFIER) { if (node->token.type != T_IDENTIFIER) {
PrintError2(tokenizer, node, "Expected the name of the inttype.\n"); PrintError2(tokenizer, node, "Expected the name of the inttype.\n");
return NULL; return NULL;
} }
if (TokenNext(tokenizer).type != T_LEFT_FANCY) { Token token = TokenNext(tokenizer);
if (token.type == T_ERROR) {
return NULL;
} else if (token.type == T_COLON) {
Node *parent = ParseType(tokenizer, false, false, false);
if (!parent) return NULL;
*contentLink = parent;
contentLink = &parent->sibling;
token = TokenNext(tokenizer);
node->hasTypeInheritanceParent = true;
}
if (token.type == T_ERROR) {
return NULL;
} else if (token.type != T_LEFT_FANCY) {
PrintError2(tokenizer, node, "Expected a '{' for the inttype contents after the name.\n"); PrintError2(tokenizer, node, "Expected a '{' for the inttype contents after the name.\n");
return NULL; return NULL;
} }
Node **constantLink = &node->firstChild;
while (true) { while (true) {
Token peek = TokenPeek(tokenizer); Token peek = TokenPeek(tokenizer);
if (peek.type == T_ERROR) return NULL; if (peek.type == T_ERROR) return NULL;
@ -2151,8 +2167,8 @@ Node *ParseRoot(Tokenizer *tokenizer) {
Node *constant = (Node *) AllocateFixed(sizeof(Node)); Node *constant = (Node *) AllocateFixed(sizeof(Node));
constant->token = TokenNext(tokenizer); constant->token = TokenNext(tokenizer);
constant->type = T_INTTYPE_CONSTANT; constant->type = T_INTTYPE_CONSTANT;
*constantLink = constant; *contentLink = constant;
constantLink = &constant->sibling; contentLink = &constant->sibling;
if (constant->token.type != T_IDENTIFIER) { if (constant->token.type != T_IDENTIFIER) {
PrintError2(tokenizer, constant, "Expected an identifier for the constant.\n"); PrintError2(tokenizer, constant, "Expected an identifier for the constant.\n");
@ -2644,9 +2660,14 @@ bool ASTLookupTypeIdentifiers(Tokenizer *tokenizer, Node *node) {
} }
} }
if (node->type == T_DECLARE || node->type == T_ARGUMENT || node->type == T_NEW || node->type == T_LIST || node->type == T_HANDLETYPE) { if (node->type == T_DECLARE || node->type == T_ARGUMENT || node->type == T_NEW || node->type == T_LIST || node->hasTypeInheritanceParent) {
Node *type = node->firstChild; Node *type = node->firstChild;
if (node->hasTypeInheritanceParent && type && type->type != T_IDENTIFIER) {
PrintError2(tokenizer, node, "Types can only inherit from similar types.\n");
return false;
}
if (type && type->type == T_IDENTIFIER) { if (type && type->type == T_IDENTIFIER) {
Node *lookup = ScopeLookup(tokenizer, type, false); Node *lookup = ScopeLookup(tokenizer, type, false);
@ -2654,9 +2675,9 @@ bool ASTLookupTypeIdentifiers(Tokenizer *tokenizer, Node *node) {
return false; return false;
} }
if (node->type == T_HANDLETYPE) { if (node->hasTypeInheritanceParent) {
if (lookup->type != T_HANDLETYPE) { if (lookup->type != node->type) {
PrintError2(tokenizer, lookup, "handletypes can only inherit from other handletypes.\n"); PrintError2(tokenizer, node, "Types can only inherit from similar types.\n");
return false; return false;
} }
} else if (!node->expressionType) { } else if (!node->expressionType) {
@ -2670,18 +2691,19 @@ bool ASTLookupTypeIdentifiers(Tokenizer *tokenizer, Node *node) {
} else if (lookup->type == T_FUNCTYPE) { } else if (lookup->type == T_FUNCTYPE) {
MemoryCopy(node->expressionType, lookup->firstChild, sizeof(Node)); MemoryCopy(node->expressionType, lookup->firstChild, sizeof(Node));
} else if (lookup->type == T_STRUCT || lookup->type == T_INTTYPE || lookup->type == T_HANDLETYPE) { } else if (lookup->type == T_STRUCT || lookup->type == T_INTTYPE || lookup->type == T_HANDLETYPE) {
if (node->type == T_HANDLETYPE) { if (node->hasTypeInheritanceParent) {
if (lookup->cycleCheck) { if (lookup->cycleCheck) {
PrintError2(tokenizer, lookup, "Cyclic handletype inheritance.\n"); PrintError2(tokenizer, lookup, "Cyclic type inheritance.\n");
return false; return false;
} }
Node *copy = (Node *) AllocateFixed(sizeof(Node)); Node *copy = (Node *) AllocateFixed(sizeof(Node));
*copy = *lookup; *copy = *lookup;
copy->sibling = NULL; copy->sibling = node->firstChild->sibling;
node->firstChild = copy; node->firstChild = copy;
node->cycleCheck = true; node->cycleCheck = true;
if (!ASTLookupTypeIdentifiers(tokenizer, copy)) return false; if (!ASTLookupTypeIdentifiers(tokenizer, copy)) return false;
node->cycleCheck = false;
} else { } else {
MemoryCopy(node->expressionType, lookup, sizeof(Node)); MemoryCopy(node->expressionType, lookup, sizeof(Node));
} }
@ -2703,8 +2725,13 @@ bool ASTImplicitCastIsPossible(Node *targetType, Node *expressionType) {
} else if (targetType->type == T_ERR && ASTMatching(targetType->firstChild, expressionType)) { } else if (targetType->type == T_ERR && ASTMatching(targetType->firstChild, expressionType)) {
return true; return true;
} else if (targetType->type == T_HANDLETYPE && expressionType->type == T_HANDLETYPE) { } else if (targetType->type == T_HANDLETYPE && expressionType->type == T_HANDLETYPE) {
// Only allow implicit casts to the inherited type.
Node *inherit = expressionType->firstChild; Node *inherit = expressionType->firstChild;
return inherit && (ASTMatching(targetType, inherit) || ASTImplicitCastIsPossible(targetType, inherit)); return inherit && (ASTMatching(targetType, inherit) || ASTImplicitCastIsPossible(targetType, inherit));
} else if (targetType->type == T_INTTYPE && expressionType->type == T_INTTYPE) {
// Only allow implicit casts to a type that inherits from this.
Node *inherit = targetType->firstChild;
return inherit && inherit->type != T_INTTYPE_CONSTANT && (ASTMatching(inherit, expressionType) || ASTImplicitCastIsPossible(inherit, expressionType));
} else { } else {
return false; return false;
} }
@ -2723,8 +2750,9 @@ Node *ASTImplicitCastApply(Tokenizer *tokenizer, Node *parent, Node *target, Nod
cast->parent = parent; cast->parent = parent;
cast->firstChild = expression; cast->firstChild = expression;
return cast; return cast;
} else if (target->type == T_HANDLETYPE && expression->expressionType->type == T_HANDLETYPE) { } else if ((target->type == T_HANDLETYPE && expression->expressionType->type == T_HANDLETYPE)
return expression; // Nothing needs to be done to cast between handletypes. || (target->type == T_INTTYPE && expression->expressionType->type == T_INTTYPE)) {
return expression; // Nothing needs to be done to cast between handletypes or inttypes.
} else { } else {
Assert(false); Assert(false);
return NULL; return NULL;