mirror of https://gitlab.com/nakst/essence
scripting engine: bugfixes
This commit is contained in:
parent
d2aea44158
commit
be8686282d
|
@ -24,9 +24,11 @@ You can download and test the latest nightly build from https://github.com/nakst
|
||||||
|
|
||||||
These builds are configured to run on emulators only, to make testing easier. Builds for real hardware are coming soon :)
|
These builds are configured to run on emulators only, to make testing easier. Builds for real hardware are coming soon :)
|
||||||
|
|
||||||
## Building
|
## Source
|
||||||
|
|
||||||
See `help/Building.md` for a description of how to build and test the system.
|
See `help/Building.md` for a description of how to build and test the system from source.
|
||||||
|
|
||||||
|
For an overview of the files in the source tree, see help/Source Map.md.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,10 @@
|
||||||
// - Using declared types from imported modules.
|
// - Using declared types from imported modules.
|
||||||
// - struct inheritance.
|
// - struct inheritance.
|
||||||
|
|
||||||
|
// TODO Syntax sugar: (ideas)
|
||||||
|
// - Pipe operator? e.g. <e := expression> | <f := function pointer> (...) ==> f(e, ...)
|
||||||
|
// - Dot operator for functions? e.g. <f := function pointer> . ==> f()
|
||||||
|
|
||||||
// TODO Larger missing features:
|
// TODO Larger missing features:
|
||||||
// - Serialization.
|
// - Serialization.
|
||||||
// - Debugging.
|
// - Debugging.
|
||||||
|
@ -115,6 +119,7 @@
|
||||||
#define T_ANYTYPE_CAST (94)
|
#define T_ANYTYPE_CAST (94)
|
||||||
#define T_CAST_TYPE_WRAPPER (95)
|
#define T_CAST_TYPE_WRAPPER (95)
|
||||||
#define T_ZERO (96)
|
#define T_ZERO (96)
|
||||||
|
#define T_PLACEHOLDER (97)
|
||||||
|
|
||||||
#define T_EXIT_SCOPE (100)
|
#define T_EXIT_SCOPE (100)
|
||||||
#define T_END_FUNCTION (101)
|
#define T_END_FUNCTION (101)
|
||||||
|
@ -1620,7 +1625,7 @@ Node *ParseIf(Tokenizer *tokenizer) {
|
||||||
Token semicolon = TokenNext(tokenizer);
|
Token semicolon = TokenNext(tokenizer);
|
||||||
|
|
||||||
if (semicolon.type != T_SEMICOLON) {
|
if (semicolon.type != T_SEMICOLON) {
|
||||||
PrintError2(tokenizer, (*link)->sibling, "Expected a semicolon at the end of the expression.\n");
|
PrintError2(tokenizer, wrapper->firstChild, "Expected a semicolon at the end of the expression.\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2371,7 +2376,7 @@ Node *ParseRoot(Tokenizer *tokenizer) {
|
||||||
// --------------------------------- Scope management.
|
// --------------------------------- Scope management.
|
||||||
|
|
||||||
bool ScopeIsVariableType(Node *node) {
|
bool ScopeIsVariableType(Node *node) {
|
||||||
return node->type == T_DECLARE || node->type == T_FUNCTION || node->type == T_ARGUMENT;
|
return node->type == T_DECLARE || node->type == T_FUNCTION || node->type == T_ARGUMENT || node->type == T_PLACEHOLDER;
|
||||||
}
|
}
|
||||||
|
|
||||||
intptr_t ScopeLookupIndex(Node *node, Scope *scope, bool maybe, bool real /* if false, the variable index is returned */) {
|
intptr_t ScopeLookupIndex(Node *node, Scope *scope, bool maybe, bool real /* if false, the variable index is returned */) {
|
||||||
|
@ -2442,7 +2447,8 @@ bool ScopeCheckNotAlreadyUsed(Tokenizer *tokenizer, Node *node) {
|
||||||
for (uintptr_t i = 0; i < scope->entryCount; i++) {
|
for (uintptr_t i = 0; i < scope->entryCount; i++) {
|
||||||
if (scope->entries[i]->token.textBytes == node->token.textBytes
|
if (scope->entries[i]->token.textBytes == node->token.textBytes
|
||||||
&& 0 == MemoryCompare(scope->entries[i]->token.text, node->token.text, node->token.textBytes)
|
&& 0 == MemoryCompare(scope->entries[i]->token.text, node->token.text, node->token.textBytes)
|
||||||
&& (!scope->isRoot || node->scope == scope)) {
|
&& (!scope->isRoot || node->scope == scope)
|
||||||
|
&& scope->entries[i]->type != T_PLACEHOLDER) {
|
||||||
PrintError2(tokenizer, node, "The identifier '%.*s' was already used in this scope.\n",
|
PrintError2(tokenizer, node, "The identifier '%.*s' was already used in this scope.\n",
|
||||||
node->token.textBytes, node->token.text);
|
node->token.textBytes, node->token.text);
|
||||||
|
|
||||||
|
@ -2565,6 +2571,16 @@ bool ASTSetScopes(Tokenizer *tokenizer, ExecutionContext *context, Node *node, S
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (node->type == T_FOR_EACH) {
|
||||||
|
Node *placeholder;
|
||||||
|
placeholder = (Node *) AllocateFixed(sizeof(Node));
|
||||||
|
placeholder->type = T_PLACEHOLDER;
|
||||||
|
Assert(ScopeAddEntry(tokenizer, scope, placeholder));
|
||||||
|
placeholder = (Node *) AllocateFixed(sizeof(Node));
|
||||||
|
placeholder->type = T_PLACEHOLDER;
|
||||||
|
Assert(ScopeAddEntry(tokenizer, scope, placeholder));
|
||||||
|
}
|
||||||
|
|
||||||
if (node->type == T_IMPORT) {
|
if (node->type == T_IMPORT) {
|
||||||
ImportData *alreadyImportedModule = importedModules;
|
ImportData *alreadyImportedModule = importedModules;
|
||||||
|
|
||||||
|
@ -3093,6 +3109,7 @@ bool ASTSetTypes(Tokenizer *tokenizer, Node *node) {
|
||||||
&& !ASTMatching(leftType, &globalExpressionTypeFloat)
|
&& !ASTMatching(leftType, &globalExpressionTypeFloat)
|
||||||
&& !ASTMatching(leftType, &globalExpressionTypeStr)
|
&& !ASTMatching(leftType, &globalExpressionTypeStr)
|
||||||
&& !ASTMatching(leftType, &globalExpressionTypeBool)
|
&& !ASTMatching(leftType, &globalExpressionTypeBool)
|
||||||
|
&& !ASTIsIntType(leftType)
|
||||||
&& (!leftType || leftType->type != T_LIST)
|
&& (!leftType || leftType->type != T_LIST)
|
||||||
&& (!leftType || leftType->type != T_STRUCT)) {
|
&& (!leftType || leftType->type != T_STRUCT)) {
|
||||||
PrintError2(tokenizer, node, "These types cannot be compared.\n");
|
PrintError2(tokenizer, node, "These types cannot be compared.\n");
|
||||||
|
@ -3349,6 +3366,11 @@ bool ASTSetTypes(Tokenizer *tokenizer, Node *node) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Assert(node->scope->entryCount == 3 && node->scope->variableEntryCount == 3
|
||||||
|
&& node->scope->entries[1]->type == T_PLACEHOLDER && node->scope->entries[2]->type == T_PLACEHOLDER);
|
||||||
|
node->scope->entries[1]->expressionType = listType;
|
||||||
|
node->scope->entries[2]->expressionType = &globalExpressionTypeInt;
|
||||||
} else if (node->type == T_INDEX) {
|
} else if (node->type == T_INDEX) {
|
||||||
if (!ASTMatching(node->firstChild->expressionType, &globalExpressionTypeStr)
|
if (!ASTMatching(node->firstChild->expressionType, &globalExpressionTypeStr)
|
||||||
&& node->firstChild->expressionType->type != T_LIST) {
|
&& node->firstChild->expressionType->type != T_LIST) {
|
||||||
|
@ -3994,6 +4016,17 @@ bool FunctionBuilderRecurse(Tokenizer *tokenizer, Node *node, FunctionBuilder *b
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the scope index base.
|
||||||
|
Node *variableNode = (Node *) AllocateFixed(sizeof(Node));
|
||||||
|
variableNode->type = T_IDENTIFIER;
|
||||||
|
variableNode->token = declare->token;
|
||||||
|
variableNode->scope = node->scope;
|
||||||
|
variableNode->parent = node;
|
||||||
|
size_t oldDataBytes = builder->dataBytes;
|
||||||
|
FunctionBuilderVariable(tokenizer, builder, variableNode, true);
|
||||||
|
Assert(oldDataBytes == builder->dataBytes);
|
||||||
|
int32_t scopeIndexBase = builder->scopeIndex;
|
||||||
|
|
||||||
// Declare the iteration variable.
|
// Declare the iteration variable.
|
||||||
if (!FunctionBuilderRecurse(tokenizer, declare, builder, false)) return false;
|
if (!FunctionBuilderRecurse(tokenizer, declare, builder, false)) return false;
|
||||||
|
|
||||||
|
@ -4059,19 +4092,29 @@ bool FunctionBuilderRecurse(Tokenizer *tokenizer, Node *node, FunctionBuilder *b
|
||||||
// Stack: list, index, ...
|
// Stack: list, index, ...
|
||||||
|
|
||||||
// Set the iteration variable.
|
// Set the iteration variable.
|
||||||
Node *variableNode = (Node *) AllocateFixed(sizeof(Node));
|
|
||||||
variableNode->type = T_IDENTIFIER;
|
|
||||||
variableNode->token = declare->token;
|
|
||||||
variableNode->scope = node->scope;
|
|
||||||
variableNode->parent = node;
|
|
||||||
FunctionBuilderVariable(tokenizer, builder, variableNode, true);
|
|
||||||
b = T_EQUALS;
|
b = T_EQUALS;
|
||||||
FunctionBuilderAppend(builder, &b, sizeof(b));
|
FunctionBuilderAppend(builder, &b, sizeof(b));
|
||||||
FunctionBuilderAppend(builder, &builder->scopeIndex, sizeof(builder->scopeIndex));
|
FunctionBuilderAppend(builder, &scopeIndexBase, sizeof(scopeIndexBase));
|
||||||
|
|
||||||
|
// Save the list and index.
|
||||||
|
int32_t scopeIndexList = scopeIndexBase - 1;
|
||||||
|
int32_t scopeIndexIndex = scopeIndexBase - 2;
|
||||||
|
b = T_EQUALS;
|
||||||
|
FunctionBuilderAppend(builder, &b, sizeof(b));
|
||||||
|
FunctionBuilderAppend(builder, &scopeIndexList, sizeof(scopeIndexList));
|
||||||
|
FunctionBuilderAppend(builder, &b, sizeof(b));
|
||||||
|
FunctionBuilderAppend(builder, &scopeIndexIndex, sizeof(scopeIndexIndex));
|
||||||
|
|
||||||
// Output the body.
|
// Output the body.
|
||||||
if (!FunctionBuilderRecurse(tokenizer, body, builder, false)) return false;
|
if (!FunctionBuilderRecurse(tokenizer, body, builder, false)) return false;
|
||||||
|
|
||||||
|
// Load the list and index.
|
||||||
|
b = T_VARIABLE;
|
||||||
|
FunctionBuilderAppend(builder, &b, sizeof(b));
|
||||||
|
FunctionBuilderAppend(builder, &scopeIndexIndex, sizeof(scopeIndexIndex));
|
||||||
|
FunctionBuilderAppend(builder, &b, sizeof(b));
|
||||||
|
FunctionBuilderAppend(builder, &scopeIndexList, sizeof(scopeIndexList));
|
||||||
|
|
||||||
// Increment the index.
|
// Increment the index.
|
||||||
// Stack: list, index, ...
|
// Stack: list, index, ...
|
||||||
b = T_SWAP;
|
b = T_SWAP;
|
||||||
|
|
Loading…
Reference in New Issue