mirror of https://gitlab.com/nakst/essence
				
				
				
			scripting engine: implement T_OP_DELETE, T_OP_DELETE_MANY, and T_OP_INSERT_MANY
This commit is contained in:
		
							parent
							
								
									f3dc1fd4bb
								
							
						
					
					
						commit
						af0ba6e352
					
				
							
								
								
									
										105
									
								
								util/script.c
								
								
								
								
							
							
						
						
									
										105
									
								
								util/script.c
								
								
								
								
							| 
						 | 
					@ -1,5 +1,4 @@
 | 
				
			||||||
// TODO Basic missing features:
 | 
					// TODO Basic missing features:
 | 
				
			||||||
// 	- Other list operations: insert_many, delete_many.
 | 
					 | 
				
			||||||
// 	- Maps: T[int], T[str].
 | 
					// 	- Maps: T[int], T[str].
 | 
				
			||||||
// 	- Control flow: break, continue.
 | 
					// 	- Control flow: break, continue.
 | 
				
			||||||
// 	- Other operators: remainder, ternary.
 | 
					// 	- Other operators: remainder, ternary.
 | 
				
			||||||
| 
						 | 
					@ -31,6 +30,7 @@
 | 
				
			||||||
// 	- Setting the initial values of global variables.
 | 
					// 	- Setting the initial values of global variables.
 | 
				
			||||||
// 	- Better handling of memory allocation failures.
 | 
					// 	- Better handling of memory allocation failures.
 | 
				
			||||||
// 	- Operation arguments are evaluated in the opposite order to functions?
 | 
					// 	- Operation arguments are evaluated in the opposite order to functions?
 | 
				
			||||||
 | 
					// 	- Shrink lists during garbage collection.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <stdint.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
#include <stddef.h>
 | 
					#include <stddef.h>
 | 
				
			||||||
| 
						 | 
					@ -5452,6 +5452,109 @@ int ScriptExecuteFunction(uintptr_t instructionPointer, ExecutionContext *contex
 | 
				
			||||||
			entry->list[insertIndex] = context->c->stack[context->c->stackPointer - 2];
 | 
								entry->list[insertIndex] = context->c->stack[context->c->stackPointer - 2];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			context->c->stackPointer -= 3;
 | 
								context->c->stackPointer -= 3;
 | 
				
			||||||
 | 
							} else if (command == T_OP_INSERT_MANY) {
 | 
				
			||||||
 | 
								if (context->c->stackPointer < 3) return -1;
 | 
				
			||||||
 | 
								if (!context->c->stackIsManaged[context->c->stackPointer - 3]) return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								uint64_t index = context->c->stack[context->c->stackPointer - 3].i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!index) {
 | 
				
			||||||
 | 
									PrintError4(context, instructionPointer - 1, "The list is null.\n");
 | 
				
			||||||
 | 
									return 0;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (context->heapEntriesAllocated <= index) return -1;
 | 
				
			||||||
 | 
								HeapEntry *entry = &context->heap[index];
 | 
				
			||||||
 | 
								if (entry->type != T_LIST) return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (context->c->stackIsManaged[context->c->stackPointer - 1]) return -1;
 | 
				
			||||||
 | 
								int64_t insertCount = context->c->stack[context->c->stackPointer - 1].i;
 | 
				
			||||||
 | 
								int64_t newLength = (int64_t) entry->length + insertCount;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (insertCount < 0) {
 | 
				
			||||||
 | 
									PrintError4(context, instructionPointer - 1, "The number of items to insert is negative (%ld).\n", insertCount);
 | 
				
			||||||
 | 
									return 0;
 | 
				
			||||||
 | 
								} else if (newLength < 0 || newLength >= 1000000000) {
 | 
				
			||||||
 | 
									PrintError4(context, instructionPointer - 1, "The new length of the list (%ld + %ld = %ld) "
 | 
				
			||||||
 | 
											"is out of the supported range (0..1000000000).\n", (int64_t) entry->length, insertCount, newLength);
 | 
				
			||||||
 | 
									return 0;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								uint32_t oldLength = context->heap[index].length;
 | 
				
			||||||
 | 
								entry->length = newLength;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (entry->length > entry->allocated) {
 | 
				
			||||||
 | 
									// TODO Handling out of memory errors.
 | 
				
			||||||
 | 
									entry->allocated = entry->allocated ? entry->allocated * 2 : 4;
 | 
				
			||||||
 | 
									if (entry->length > entry->allocated) entry->allocated = entry->length + 5;
 | 
				
			||||||
 | 
									entry->list = (Value *) AllocateResize(entry->list, entry->allocated * sizeof(Value));
 | 
				
			||||||
 | 
									Assert(entry->length <= entry->allocated);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (context->c->stackIsManaged[context->c->stackPointer - 2]) return -1;
 | 
				
			||||||
 | 
								int64_t insertIndex = context->c->stack[context->c->stackPointer - 2].i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (insertIndex < 0 || insertIndex > oldLength) {
 | 
				
			||||||
 | 
									PrintError4(context, instructionPointer - 1, "Cannot insert at index %ld. The list has length %ld.\n",
 | 
				
			||||||
 | 
											insertIndex, oldLength);
 | 
				
			||||||
 | 
									return 0;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								for (int64_t i = oldLength - 1; i >= insertIndex; i--) {
 | 
				
			||||||
 | 
									entry->list[i + insertCount] = entry->list[i];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								for (uintptr_t i = 0; i < (uintptr_t) insertCount; i++) {
 | 
				
			||||||
 | 
									entry->list[i + insertIndex].i = 0;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								context->c->stackPointer -= 3;
 | 
				
			||||||
 | 
							} else if (command == T_OP_DELETE || command == T_OP_DELETE_MANY) {
 | 
				
			||||||
 | 
								int stackIndexList = command == T_OP_DELETE ? 2 : 3;
 | 
				
			||||||
 | 
								int stackIndexIndex = command == T_OP_DELETE ? 1 : 2;
 | 
				
			||||||
 | 
								if (context->c->stackPointer < (uintptr_t) stackIndexList) return -1;
 | 
				
			||||||
 | 
								if (!context->c->stackIsManaged[context->c->stackPointer - stackIndexList]) return -1;
 | 
				
			||||||
 | 
								uint64_t index = context->c->stack[context->c->stackPointer - stackIndexList].i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!index) {
 | 
				
			||||||
 | 
									PrintError4(context, instructionPointer - 1, "The list is null.\n");
 | 
				
			||||||
 | 
									return 0;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (context->heapEntriesAllocated <= index) return -1;
 | 
				
			||||||
 | 
								HeapEntry *entry = &context->heap[index];
 | 
				
			||||||
 | 
								if (entry->type != T_LIST) return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (context->c->stackIsManaged[context->c->stackPointer - 1]) return -1;
 | 
				
			||||||
 | 
								int64_t deleteCount = command == T_OP_DELETE ? 1 : context->c->stack[context->c->stackPointer - 1].i;
 | 
				
			||||||
 | 
								int64_t newLength = (int64_t) entry->length - deleteCount;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (deleteCount < 0) {
 | 
				
			||||||
 | 
									PrintError4(context, instructionPointer - 1, "The number of items to delete is negative (%ld).\n", deleteCount);
 | 
				
			||||||
 | 
									return 0;
 | 
				
			||||||
 | 
								} else if (newLength < 0 || newLength >= 1000000000) {
 | 
				
			||||||
 | 
									PrintError4(context, instructionPointer - 1, "The new length of the list (%ld - %ld = %ld) "
 | 
				
			||||||
 | 
											"is out of the supported range (0..1000000000).\n", (int64_t) entry->length, deleteCount, newLength);
 | 
				
			||||||
 | 
									return 0;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// TODO Maybe shrink the list storage, if it will save a lot of memory.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (context->c->stackIsManaged[context->c->stackPointer - stackIndexIndex]) return -1;
 | 
				
			||||||
 | 
								int64_t deleteIndex = context->c->stack[context->c->stackPointer - stackIndexIndex].i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (deleteIndex < 0 || deleteIndex > newLength) {
 | 
				
			||||||
 | 
									PrintError4(context, instructionPointer - 1, "Cannot delete %ld items starting at index %ld. The list has length %ld.\n",
 | 
				
			||||||
 | 
											deleteCount, deleteIndex, (int64_t) entry->length);
 | 
				
			||||||
 | 
									return 0;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								for (int64_t i = deleteIndex; i < newLength; i++) {
 | 
				
			||||||
 | 
									entry->list[i] = entry->list[i + deleteCount];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								entry->length = newLength;
 | 
				
			||||||
 | 
								context->c->stackPointer -= command == T_OP_DELETE ? 2 : 3;
 | 
				
			||||||
		} else if (command == T_OP_DELETE_ALL) {
 | 
							} else if (command == T_OP_DELETE_ALL) {
 | 
				
			||||||
			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