Skip to content

Commit

Permalink
Add delete keyword to delete variables and object items
Browse files Browse the repository at this point in the history
  • Loading branch information
James-Livesey committed Jul 16, 2024
1 parent 04d1b71 commit e06681b
Show file tree
Hide file tree
Showing 11 changed files with 175 additions and 11 deletions.
39 changes: 34 additions & 5 deletions dist/libvoxel.h
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,7 @@ typedef enum voxel_TokenType {
VOXEL_TOKEN_TYPE_GET = '?',
VOXEL_TOKEN_TYPE_SET = ':',
VOXEL_TOKEN_TYPE_VAR = 'v',
VOXEL_TOKEN_TYPE_DELETE = 'D',
VOXEL_TOKEN_TYPE_POP = 'p',
VOXEL_TOKEN_TYPE_DUPE = 'd',
VOXEL_TOKEN_TYPE_OVER = 'o',
Expand Down Expand Up @@ -567,6 +568,7 @@ VOXEL_ERRORABLE voxel_destroyScope(voxel_Scope* scope);
voxel_ObjectItem* voxel_getScopeItem(voxel_Scope* scope, voxel_Thing* key);
VOXEL_ERRORABLE voxel_setScopeItem(voxel_Scope* scope, voxel_Thing* key, voxel_Thing* value);
VOXEL_ERRORABLE voxel_setLocalScopeItem(voxel_Scope* scope, voxel_Thing* key, voxel_Thing* value);
VOXEL_ERRORABLE voxel_removeScopeItem(voxel_Scope* scope, voxel_Thing* key);

voxel_Executor* voxel_newExecutor(voxel_Context* context);
voxel_Executor* voxel_cloneExecutor(voxel_Executor* executor, voxel_Bool copyValueStack);
Expand Down Expand Up @@ -1343,12 +1345,10 @@ void voxel_builtins_core_removeObjectItem(voxel_Executor* executor) {
voxel_Thing* key = voxel_pop(executor);
voxel_Thing* object = voxel_pop(executor);

if (!object || object->type != VOXEL_TYPE_OBJECT || object->isLocked || argCount < 2) {
return voxel_pushNull(executor);
if (object && object->type == VOXEL_TYPE_OBJECT && !object->isLocked && argCount >= 2) {
voxel_removeObjectItem(executor->context, object, key);
}

voxel_removeObjectItem(executor->context, object, key);

voxel_unreferenceThing(executor->context, key);
voxel_unreferenceThing(executor->context, object);

Expand Down Expand Up @@ -5030,6 +5030,7 @@ VOXEL_ERRORABLE voxel_nextToken(voxel_Executor* executor, voxel_Position* positi
case VOXEL_TOKEN_TYPE_GET:
case VOXEL_TOKEN_TYPE_SET:
case VOXEL_TOKEN_TYPE_VAR:
case VOXEL_TOKEN_TYPE_DELETE:
case VOXEL_TOKEN_TYPE_POP:
case VOXEL_TOKEN_TYPE_DUPE:
case VOXEL_TOKEN_TYPE_OVER:
Expand Down Expand Up @@ -5358,7 +5359,9 @@ VOXEL_ERRORABLE voxel_stepExecutor(voxel_Executor* executor) {
VOXEL_MUST(voxel_pushOntoList(executor->context, executor->valueStack, scopeValue));
VOXEL_MUST(voxel_unreferenceThing(executor->context, (voxel_Thing*)getKey.value));

scopeValue->referenceCount++; // To ensure that builtins don't dereference the thing in the scope
if (scopeItem) {
scopeValue->referenceCount++; // To ensure that builtins don't dereference the thing in the scope
}

break;
}
Expand All @@ -5378,6 +5381,18 @@ VOXEL_ERRORABLE voxel_stepExecutor(voxel_Executor* executor) {
break;
}

case VOXEL_TOKEN_TYPE_DELETE:
{
VOXEL_ERRORABLE deleteKey = voxel_popFromList(executor->context, executor->valueStack); VOXEL_MUST(deleteKey);

VOXEL_ASSERT(deleteKey.value, VOXEL_ERROR_MISSING_ARG);

VOXEL_MUST(voxel_removeScopeItem(executor->scope, (voxel_Thing*)deleteKey.value));
VOXEL_MUST(voxel_unreferenceThing(executor->context, (voxel_Thing*)deleteKey.value));

break;
}

case VOXEL_TOKEN_TYPE_POP:
{
VOXEL_ERRORABLE popResult = voxel_popFromList(executor->context, executor->valueStack); VOXEL_MUST(popResult);
Expand Down Expand Up @@ -5758,6 +5773,20 @@ VOXEL_ERRORABLE voxel_setLocalScopeItem(voxel_Scope* scope, voxel_Thing* key, vo
return voxel_setObjectItem(scope->context, scope->things, key, value);
}

VOXEL_ERRORABLE voxel_removeScopeItem(voxel_Scope* scope, voxel_Thing* key) {
voxel_ObjectItem* thisScopeItem = voxel_getObjectItem(scope->things, key);

if (thisScopeItem) {
return voxel_removeObjectItem(scope->context, scope->things, key);
}

if (scope->parentScope) {
return voxel_removeScopeItem(scope->context->globalScope, key);
}

return VOXEL_OK;
}

// src/helpers.h

#define _VOXEL_HELPER_POP_VALUE(name, type, popCall, getValueCall, defaultValue) type name(voxel_Executor* executor) { \
Expand Down
6 changes: 2 additions & 4 deletions src/builtins/core/objects.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,10 @@ void voxel_builtins_core_removeObjectItem(voxel_Executor* executor) {
voxel_Thing* key = voxel_pop(executor);
voxel_Thing* object = voxel_pop(executor);

if (!object || object->type != VOXEL_TYPE_OBJECT || object->isLocked || argCount < 2) {
return voxel_pushNull(executor);
if (object && object->type == VOXEL_TYPE_OBJECT && !object->isLocked && argCount >= 2) {
voxel_removeObjectItem(executor->context, object, key);
}

voxel_removeObjectItem(executor->context, object, key);

voxel_unreferenceThing(executor->context, key);
voxel_unreferenceThing(executor->context, object);

Expand Down
2 changes: 2 additions & 0 deletions src/declarations.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ typedef enum voxel_TokenType {
VOXEL_TOKEN_TYPE_GET = '?',
VOXEL_TOKEN_TYPE_SET = ':',
VOXEL_TOKEN_TYPE_VAR = 'v',
VOXEL_TOKEN_TYPE_DELETE = 'D',
VOXEL_TOKEN_TYPE_POP = 'p',
VOXEL_TOKEN_TYPE_DUPE = 'd',
VOXEL_TOKEN_TYPE_OVER = 'o',
Expand Down Expand Up @@ -372,6 +373,7 @@ VOXEL_ERRORABLE voxel_destroyScope(voxel_Scope* scope);
voxel_ObjectItem* voxel_getScopeItem(voxel_Scope* scope, voxel_Thing* key);
VOXEL_ERRORABLE voxel_setScopeItem(voxel_Scope* scope, voxel_Thing* key, voxel_Thing* value);
VOXEL_ERRORABLE voxel_setLocalScopeItem(voxel_Scope* scope, voxel_Thing* key, voxel_Thing* value);
VOXEL_ERRORABLE voxel_removeScopeItem(voxel_Scope* scope, voxel_Thing* key);

voxel_Executor* voxel_newExecutor(voxel_Context* context);
voxel_Executor* voxel_cloneExecutor(voxel_Executor* executor, voxel_Bool copyValueStack);
Expand Down
16 changes: 15 additions & 1 deletion src/executors.h
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,9 @@ VOXEL_ERRORABLE voxel_stepExecutor(voxel_Executor* executor) {
VOXEL_MUST(voxel_pushOntoList(executor->context, executor->valueStack, scopeValue));
VOXEL_MUST(voxel_unreferenceThing(executor->context, (voxel_Thing*)getKey.value));

scopeValue->referenceCount++; // To ensure that builtins don't dereference the thing in the scope
if (scopeItem) {
scopeValue->referenceCount++; // To ensure that builtins don't dereference the thing in the scope
}

break;
}
Expand All @@ -280,6 +282,18 @@ VOXEL_ERRORABLE voxel_stepExecutor(voxel_Executor* executor) {
break;
}

case VOXEL_TOKEN_TYPE_DELETE:
{
VOXEL_ERRORABLE deleteKey = voxel_popFromList(executor->context, executor->valueStack); VOXEL_MUST(deleteKey);

VOXEL_ASSERT(deleteKey.value, VOXEL_ERROR_MISSING_ARG);

VOXEL_MUST(voxel_removeScopeItem(executor->scope, (voxel_Thing*)deleteKey.value));
VOXEL_MUST(voxel_unreferenceThing(executor->context, (voxel_Thing*)deleteKey.value));

break;
}

case VOXEL_TOKEN_TYPE_POP:
{
VOXEL_ERRORABLE popResult = voxel_popFromList(executor->context, executor->valueStack); VOXEL_MUST(popResult);
Expand Down
1 change: 1 addition & 0 deletions src/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ VOXEL_ERRORABLE voxel_nextToken(voxel_Executor* executor, voxel_Position* positi
case VOXEL_TOKEN_TYPE_GET:
case VOXEL_TOKEN_TYPE_SET:
case VOXEL_TOKEN_TYPE_VAR:
case VOXEL_TOKEN_TYPE_DELETE:
case VOXEL_TOKEN_TYPE_POP:
case VOXEL_TOKEN_TYPE_DUPE:
case VOXEL_TOKEN_TYPE_OVER:
Expand Down
14 changes: 14 additions & 0 deletions src/scopes.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,18 @@ VOXEL_ERRORABLE voxel_setScopeItem(voxel_Scope* scope, voxel_Thing* key, voxel_T

VOXEL_ERRORABLE voxel_setLocalScopeItem(voxel_Scope* scope, voxel_Thing* key, voxel_Thing* value) {
return voxel_setObjectItem(scope->context, scope->things, key, value);
}

VOXEL_ERRORABLE voxel_removeScopeItem(voxel_Scope* scope, voxel_Thing* key) {
voxel_ObjectItem* thisScopeItem = voxel_getObjectItem(scope->things, key);

if (thisScopeItem) {
return voxel_removeObjectItem(scope->context, scope->things, key);
}

if (scope->parentScope) {
return voxel_removeScopeItem(scope->context->globalScope, key);
}

return VOXEL_OK;
}
8 changes: 8 additions & 0 deletions test/delete/expected.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Before deletion: hello
After deletion: null
Before index accessor deletion: value1
After index accessor deletion: null
Attempt deletion of non-object index accessor: null
Before property accessor deletion: value2
After property accessor deletion: null
Attempt deletion of non-object property accessor: null
44 changes: 44 additions & 0 deletions test/delete/main.vxl
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
var value = "hello";

syscall io_out("Before deletion: ");
syscall io_out(value);
syscall io_out("\n");

delete value;

syscall io_out("After deletion: ");
syscall io_out(value);
syscall io_out("\n");

var object = {
"key": "value1",
prop: "value2"
};

syscall io_out("Before index accessor deletion: ");
syscall io_out(object["key"]);
syscall io_out("\n");

delete object["key"];

syscall io_out("After index accessor deletion: ");
syscall io_out(object["key"]);
syscall io_out("\n");

syscall io_out("Attempt deletion of non-object index accessor: ");
syscall io_out(value["key"]);
syscall io_out("\n");

syscall io_out("Before property accessor deletion: ");
syscall io_out(object.prop);
syscall io_out("\n");

delete object.prop;

syscall io_out("After property accessor deletion: ");
syscall io_out(object.prop);
syscall io_out("\n");

syscall io_out("Attempt deletion of non-object property accessor: ");
syscall io_out(value.prop);
syscall io_out("\n");
1 change: 1 addition & 0 deletions tools/vxbuild-js/codegen.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export const vxcTokens = {
GET: byte("?"),
SET: byte(":"),
VAR: byte("v"),
DELETE: byte("D"),
POP: byte("p"),
DUPE: byte("d"),
OVER: byte("o"),
Expand Down
53 changes: 53 additions & 0 deletions tools/vxbuild-js/statements.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export class StatementNode extends ast.AstNode {
EnumStatementNode,
BreakStatementNode,
ContinueStatementNode,
DeleteStatementNode,
expressions.ExpressionNode
], namespace);

Expand Down Expand Up @@ -720,4 +721,56 @@ export class ContinueStatementNode extends ast.AstNode {
codeGen.bytes(codeGen.vxcTokens.GET, codeGen.vxcTokens.JUMP)
);
}
}

export class DeleteStatementNode extends ast.AstNode {
static HUMAN_READABLE_NAME = "`delete` statement";

static MATCH_QUERIES = [
new ast.TokenQuery(tokeniser.KeywordToken, "delete")
];

keywordToken = null;

static create(tokens, namespace) {
var instance = new this();

instance.keywordToken = this.eat(tokens);

instance.expectChildByMatching(tokens, [expressions.ExpressionThingNode], namespace);

return instance;
}

generateCode(options) {
var targetInstance = this.children[0];
var target = targetInstance.children.at(-1);

if (target instanceof expressions.FunctionCallNode) {
throw new sources.SourceError("Expected an identifier (cannot delete the return value of a function)", this.keywordToken?.sourceContainer, this.keywordToken?.location);
}

if (target instanceof expressions.IndexAccessorNode || target instanceof expressions.PropertyAccessorNode) {
var accessor = targetInstance.children.pop();

return codeGen.join(
targetInstance.generateCode(options),
target instanceof expressions.PropertyAccessorNode ? accessor.propertySymbol.generateCode(options) : accessor.children[0].generateCode(options),
codeGen.number(2),
codeGen.systemCall("Or"),
codeGen.bytes(codeGen.vxcTokens.POP)
);
}

if (target instanceof expressions.ThingNode) {
if (target.value instanceof namespaces.Symbol) {
return codeGen.join(
target.value.generateCode(options),
codeGen.bytes(codeGen.vxcTokens.DELETE)
);
}
}

throw new sources.SourceError("Expected an identifier", this.keywordToken?.sourceContainer, this.keywordToken?.location);
}
}
2 changes: 1 addition & 1 deletion tools/vxbuild-js/tokeniser.js
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ export function tokenise(sourceContainer) {
continue;
}

if (matchToken(/^(?:syscall|import|as|return|function|class|extends|get|set|this|super|new|var|if|else|while|for|retain|throw|try|catch|enum|break|continue)\b/)) {
if (matchToken(/^(?:syscall|import|as|return|function|class|extends|get|set|this|super|new|var|if|else|while|for|retain|throw|try|catch|enum|break|continue|delete)\b/)) {
addToken(KeywordToken);
continue;
}
Expand Down

0 comments on commit e06681b

Please sign in to comment.