Added tables to the scripts, untested

This also has a lot of bugfixing.
This commit is contained in:
2024-12-24 16:08:42 +11:00
parent 4faa0c0476
commit b092b8ce50
12 changed files with 371 additions and 55 deletions

View File

@@ -5,11 +5,6 @@
#include <stdlib.h>
Toy_Array* Toy_resizeArray(Toy_Array* paramArray, unsigned int capacity) {
if (capacity == 0) {
free(paramArray);
return NULL;
}
//if some values will be removed, free them first
if (paramArray != NULL && paramArray->count > capacity) {
for (unsigned int i = capacity; i < paramArray->count; i++) {
@@ -17,6 +12,12 @@ Toy_Array* Toy_resizeArray(Toy_Array* paramArray, unsigned int capacity) {
}
}
//if you're freeing everything, just return
if (capacity == 0) {
free(paramArray);
return NULL;
}
unsigned int originalCapacity = paramArray == NULL ? 0 : paramArray->capacity;
Toy_Array* array = realloc(paramArray, capacity * sizeof(Toy_Value) + sizeof(Toy_Array));

View File

@@ -60,9 +60,10 @@ typedef enum Toy_AstFlag {
TOY_AST_FLAG_COMPARE_GREATER_EQUAL = 25,
TOY_AST_FLAG_COMPOUND_ARRAY = 30,
// TOY_AST_FLAG_COMPOUND_TABLE = 31,
TOY_AST_FLAG_COMPOUND_TABLE = 31,
TOY_AST_FLAG_COLLECTION = 32,
TOY_AST_FLAG_INDEX = 33,
TOY_AST_FLAG_PAIR = 33,
TOY_AST_FLAG_INDEX = 34,
TOY_AST_FLAG_AND = 40,
TOY_AST_FLAG_OR = 41,

View File

@@ -206,7 +206,7 @@ static ParsingTuple parsingRulesetTable[] = {
{PREC_OR,NULL,binary},// TOY_TOKEN_OPERATOR_OR,
{PREC_NONE,unary,NULL},// TOY_TOKEN_OPERATOR_NEGATE,
{PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_QUESTION,
{PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_COLON,
{PREC_GROUP,compound,aggregate},// TOY_TOKEN_OPERATOR_COLON,
{PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_SEMICOLON, // ;
{PREC_GROUP,NULL,aggregate},// TOY_TOKEN_OPERATOR_COMMA, // ,
@@ -576,21 +576,39 @@ static Toy_AstFlag compound(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_A
return TOY_AST_FLAG_NONE;
}
//BUGFIX: special case for empty tables
if (match(parser, TOY_TOKEN_OPERATOR_COLON)) {
consume(parser, TOY_TOKEN_OPERATOR_BRACKET_RIGHT, "Expected ']' at the end of empty table");
Toy_private_emitAstPass(bucketHandle, rootHandle);
Toy_private_emitAstAggregate(bucketHandle, rootHandle, TOY_AST_FLAG_PAIR, *rootHandle);
Toy_private_emitAstCompound(bucketHandle, rootHandle, TOY_AST_FLAG_COMPOUND_TABLE);
return TOY_AST_FLAG_NONE;
}
parsePrecedence(bucketHandle, parser, rootHandle, PREC_GROUP);
//peek inside to see what you have
Toy_AstFlag flag = TOY_AST_FLAG_NONE;
if ((*rootHandle)->type == TOY_AST_AGGREGATE) {
//1 element in a table will mean the top-level node is a collection
flag = (*rootHandle)->aggregate.flag;
//more than 1 element in a table will mean you need to check the last element in the collection to find a pair
if (flag == TOY_AST_FLAG_COLLECTION && (*rootHandle)->aggregate.right->type == TOY_AST_AGGREGATE) {
flag = (*rootHandle)->aggregate.right->aggregate.flag; //yes, this is hacky
}
}
//BUGFIX: special case for trailing commas
if (parser->previous.type == TOY_TOKEN_OPERATOR_BRACKET_RIGHT && parser->current.type != TOY_TOKEN_OPERATOR_BRACKET_RIGHT) {
Toy_private_emitAstCompound(bucketHandle, rootHandle, TOY_AST_FLAG_COMPOUND_ARRAY);
//NOTE: will probably need tweaking for tables
Toy_private_emitAstCompound(bucketHandle, rootHandle, flag == TOY_AST_FLAG_PAIR ? TOY_AST_FLAG_COMPOUND_TABLE : TOY_AST_FLAG_COMPOUND_ARRAY);
return TOY_AST_FLAG_NONE;
}
consume(parser, TOY_TOKEN_OPERATOR_BRACKET_RIGHT, "Expected ']' at the end of compound expression");
Toy_private_emitAstCompound(bucketHandle, rootHandle, TOY_AST_FLAG_COMPOUND_ARRAY);
Toy_private_emitAstCompound(bucketHandle, rootHandle, flag == TOY_AST_FLAG_PAIR ? TOY_AST_FLAG_COMPOUND_TABLE : TOY_AST_FLAG_COMPOUND_ARRAY);
return TOY_AST_FLAG_NONE;
//TODO: read in a table
}
else if (parser->previous.type == TOY_TOKEN_OPERATOR_BRACKET_RIGHT) {
//allows for trailing commas
@@ -613,6 +631,10 @@ static Toy_AstFlag aggregate(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_
parsePrecedence(bucketHandle, parser, rootHandle, PREC_GROUP); //NOT +1, as compounds are right-recursive
return TOY_AST_FLAG_COLLECTION;
}
if (parser->previous.type == TOY_TOKEN_OPERATOR_COLON) {
parsePrecedence(bucketHandle, parser, rootHandle, PREC_GROUP); //NOT +1, as compounds are right-recursive
return TOY_AST_FLAG_PAIR;
}
else if (parser->previous.type == TOY_TOKEN_OPERATOR_BRACKET_LEFT) {
parsePrecedence(bucketHandle, parser, rootHandle, PREC_GROUP);
consume(parser, TOY_TOKEN_OPERATOR_BRACKET_RIGHT, "Expected ']' at the end of index expression");

View File

@@ -266,7 +266,7 @@ static unsigned int writeInstructionCompound(Toy_Routine** rt, Toy_AstCompound a
unsigned int result = writeRoutineCode(rt, ast.child);
if (ast.flag == TOY_AST_FLAG_COMPOUND_ARRAY) {
//signal how many values to read in as an array value
//signal how many values to read in as array elements
EMIT_BYTE(rt, code, TOY_OPCODE_READ);
EMIT_BYTE(rt, code, TOY_VALUE_ARRAY);
@@ -279,6 +279,20 @@ static unsigned int writeInstructionCompound(Toy_Routine** rt, Toy_AstCompound a
return 1; //leaves only 1 value on the stack
}
if (ast.flag == TOY_AST_FLAG_COMPOUND_TABLE) {
//signal how many values to read in as table elements
EMIT_BYTE(rt, code, TOY_OPCODE_READ);
EMIT_BYTE(rt, code, TOY_VALUE_TABLE);
//4-byte alignment
EMIT_BYTE(rt, code,0);
EMIT_BYTE(rt, code,0);
//how many elements
EMIT_INT(rt, code, result);
return 1; //leaves only 1 value on the stack
}
else {
fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid AST compound flag found\n" TOY_CC_RESET);
exit(-1);
@@ -297,6 +311,10 @@ static unsigned int writeInstructionAggregate(Toy_Routine** rt, Toy_AstAggregate
//collections are handled above
return result;
}
else if (ast.flag == TOY_AST_FLAG_PAIR) {
//pairs are handled above
return result;
}
else if (ast.flag == TOY_AST_FLAG_INDEX) {
//value[index, length]
EMIT_BYTE(rt, code, TOY_OPCODE_INDEX);

View File

@@ -175,7 +175,7 @@ Toy_Value* Toy_accessScopeAsPointer(Toy_Scope* scope, Toy_String* key) {
char buffer[key->info.length + 256];
sprintf(buffer, "Undefined variable: %s\n", key->name.data);
Toy_error(buffer);
NULL;
return NULL;
}
return &(entryPtr->value);

View File

@@ -114,7 +114,7 @@ void Toy_insertTable(Toy_Table** tableHandle, Toy_Value key, Toy_Value value) {
probeAndInsert(tableHandle, key, value);
}
Toy_Value Toy_lookupTable(Toy_Table** tableHandle, Toy_Value key) {
Toy_TableEntry* Toy_private_lookupTableEntryPtr(Toy_Table** tableHandle, Toy_Value key) {
if (TOY_VALUE_IS_NULL(key) || TOY_VALUE_IS_BOOLEAN(key)) { //TODO: disallow functions and opaques
Toy_error(TOY_CC_ERROR "ERROR: Bad table key\n" TOY_CC_RESET);
}
@@ -125,12 +125,12 @@ Toy_Value Toy_lookupTable(Toy_Table** tableHandle, Toy_Value key) {
while (true) {
//found the entry
if (Toy_checkValuesAreEqual((*tableHandle)->data[probe].key, key)) {
return (*tableHandle)->data[probe].value;
return (*tableHandle)->data + probe;
}
//if its an empty slot
if (TOY_VALUE_IS_NULL((*tableHandle)->data[probe].key)) {
return TOY_VALUE_FROM_NULL();
return NULL;
}
//adjust and continue
@@ -139,6 +139,18 @@ Toy_Value Toy_lookupTable(Toy_Table** tableHandle, Toy_Value key) {
}
}
Toy_Value Toy_lookupTable(Toy_Table** tableHandle, Toy_Value key) {
//TODO: I hacked this in at a moment's notice, clean it up
Toy_TableEntry* entry = Toy_private_lookupTableEntryPtr(tableHandle, key);
if (entry == NULL) {
return TOY_VALUE_FROM_NULL();
}
else {
return entry->value;
}
}
void Toy_removeTable(Toy_Table** tableHandle, Toy_Value key) {
if (TOY_VALUE_IS_NULL(key) || TOY_VALUE_IS_BOOLEAN(key)) { //TODO: disallow functions and opaques
Toy_error(TOY_CC_ERROR "ERROR: Bad table key\n" TOY_CC_RESET);

View File

@@ -10,7 +10,7 @@ typedef struct Toy_TableEntry { //32 | 64 BITNESS
unsigned int psl; //4 | 4
} Toy_TableEntry; //20 | 20
//key-value table (contains = count + tombstones)
//key-value table
typedef struct Toy_Table { //32 | 64 BITNESS
unsigned int capacity; //4 | 4
unsigned int count; //4 | 4
@@ -26,7 +26,8 @@ TOY_API Toy_Value Toy_lookupTable(Toy_Table** tableHandle, Toy_Value key);
TOY_API void Toy_removeTable(Toy_Table** tableHandle, Toy_Value key);
//NOTE: exposed to skip unnecessary allocations within Toy_Scope
TOY_API Toy_Table* Toy_private_adjustTableCapacity(Toy_Table* oldTable, unsigned int newCapacity);
TOY_API Toy_Table* Toy_private_adjustTableCapacity(Toy_Table* oldTable, unsigned int newCapacity); //TODO: make it public
TOY_API Toy_TableEntry* Toy_private_lookupTableEntryPtr(Toy_Table** tableHandle, Toy_Value key); //TODO: make it public?
//some useful sizes, could be swapped out as needed
#ifndef TOY_TABLE_INITIAL_CAPACITY

View File

@@ -4,6 +4,7 @@
#include "toy_bucket.h"
#include "toy_string.h"
#include "toy_array.h"
#include "toy_table.h"
#include <stdio.h>
#include <stdlib.h>
@@ -59,7 +60,21 @@ unsigned int Toy_hashValue(Toy_Value value) {
return hash;
}
case TOY_VALUE_TABLE:
case TOY_VALUE_TABLE: {
//since table internals can change, recalc the hash each time it's needed
Toy_Table* ptr = value.as.table;
unsigned int hash = 0;
for (unsigned int i = 0; i < ptr->capacity; i++) {
if (TOY_VALUE_IS_NULL(ptr->data[i].key) != true) {
hash ^= Toy_hashValue(ptr->data[i].key);
hash ^= Toy_hashValue(ptr->data[i].value);
}
}
return hash;
}
case TOY_VALUE_FUNCTION:
case TOY_VALUE_OPAQUE:
case TOY_VALUE_TYPE:
@@ -102,7 +117,23 @@ Toy_Value Toy_copyValue(Toy_Value value) {
return TOY_VALUE_FROM_ARRAY(result);
}
case TOY_VALUE_TABLE:
case TOY_VALUE_TABLE: {
//tables probably won't get copied much
Toy_Table* ptr = value.as.table;
Toy_Table* result = Toy_private_adjustTableCapacity(NULL, ptr->capacity);
for (unsigned int i = 0; i < ptr->capacity; i++) {
if (TOY_VALUE_IS_NULL(ptr->data[i].key) != true) {
result->data[i].key = Toy_copyValue(ptr->data[i].key);
result->data[i].value = Toy_copyValue(ptr->data[i].value);
}
}
result->capacity = ptr->capacity;
result->count = ptr->count;
return TOY_VALUE_FROM_TABLE(result);
}
case TOY_VALUE_FUNCTION:
case TOY_VALUE_OPAQUE:
case TOY_VALUE_TYPE:
@@ -130,22 +161,18 @@ void Toy_freeValue(Toy_Value value) {
break;
}
case TOY_VALUE_ARRAY: {
Toy_Array* ptr = value.as.array;
for (unsigned int i = 0; i < ptr->count; i++) {
Toy_freeValue(ptr->data[i]);
}
Toy_resizeArray(ptr, 0);
case TOY_VALUE_ARRAY:
Toy_resizeArray(value.as.array, 0);
break;
case TOY_VALUE_TABLE:
Toy_freeTable(value.as.table);
break;
}
case TOY_VALUE_REFERENCE:
//don't free references
return;
case TOY_VALUE_TABLE:
case TOY_VALUE_FUNCTION:
case TOY_VALUE_OPAQUE:
case TOY_VALUE_TYPE:
@@ -183,7 +210,7 @@ bool Toy_checkValuesAreEqual(Toy_Value left, Toy_Value right) {
return right.type == TOY_VALUE_NULL;
case TOY_VALUE_BOOLEAN:
return right.type == TOY_VALUE_NULL && left.as.boolean == right.as.boolean;
return right.type == TOY_VALUE_BOOLEAN && left.as.boolean == right.as.boolean;
case TOY_VALUE_INTEGER:
if (right.type == TOY_VALUE_INTEGER) {
@@ -240,7 +267,37 @@ bool Toy_checkValuesAreEqual(Toy_Value left, Toy_Value right) {
return true;
}
case TOY_VALUE_TABLE:
case TOY_VALUE_TABLE: {
if (right.type == TOY_VALUE_TABLE) {
Toy_Table* leftTable = left.as.table;
Toy_Table* rightTable = right.as.table;
//different counts
if (leftTable->count != rightTable->count) {
return false;
}
for (unsigned int i = 0; i < leftTable->capacity; i++) {
Toy_TableEntry* entry = leftTable->data + i;
if (TOY_VALUE_IS_NULL(entry->key) != true) {
//any mismatch is an easy difference
Toy_Value rightValue = Toy_lookupTable(&rightTable, entry->key);
if (TOY_VALUE_IS_NULL(rightValue) || Toy_checkValuesAreEqual(entry->value, rightValue) != true) {
return false;
}
}
}
}
else {
break;
}
//finally
return true;
}
case TOY_VALUE_FUNCTION:
case TOY_VALUE_OPAQUE:
case TOY_VALUE_TYPE:
@@ -278,6 +335,9 @@ bool Toy_checkValuesAreComparable(Toy_Value left, Toy_Value right) {
return false;
case TOY_VALUE_TABLE:
//nothing is comparable with a table
return false;
case TOY_VALUE_FUNCTION:
case TOY_VALUE_OPAQUE:
case TOY_VALUE_TYPE:
@@ -332,6 +392,8 @@ int Toy_compareValues(Toy_Value left, Toy_Value right) {
break;
case TOY_VALUE_TABLE:
break;
case TOY_VALUE_FUNCTION:
case TOY_VALUE_OPAQUE:
case TOY_VALUE_TYPE:
@@ -392,35 +454,120 @@ Toy_String* Toy_stringifyValue(Toy_Bucket** bucketHandle, Toy_Value value) {
case TOY_VALUE_ARRAY: {
//TODO: concat + free is definitely a performance nightmare, could make an append function?
Toy_Array* ptr = value.as.array;
Toy_String* string = Toy_createStringLength(bucketHandle, "[", 1);
//if array is empty, skip below
if (ptr->count == 0) {
Toy_String* empty = Toy_createString(bucketHandle, "[]");
return empty;
}
Toy_String* open = Toy_createStringLength(bucketHandle, "[", 1);
Toy_String* close = Toy_createStringLength(bucketHandle, "]", 1);
Toy_String* comma = Toy_createStringLength(bucketHandle, ",", 1); //reusable
bool needsComma = false;
Toy_String* string = open;
for (unsigned int i = 0; i < ptr->count; i++) {
//append each element
Toy_String* tmp = Toy_concatStrings(bucketHandle, string, Toy_stringifyValue(bucketHandle, ptr->data[i])); //increment ref
Toy_freeString(string); //decrement ref
string = tmp;
//if we need a comma
if (i + 1 < ptr->count) {
if (needsComma) {
Toy_String* tmp = Toy_concatStrings(bucketHandle, string, comma); //increment ref
Toy_freeString(string); //decrement ref
string = tmp;
}
//append each element
Toy_String* element = Toy_stringifyValue(bucketHandle, ptr->data[i]);
Toy_String* final = Toy_concatStrings(bucketHandle, string, element);
Toy_freeString(element);
Toy_freeString(string);
string = final;
needsComma = true;
}
//closing bracket
Toy_String* tmp = Toy_concatStrings(bucketHandle, string, Toy_createStringLength(bucketHandle, "]", 1));
Toy_String* tmp = Toy_concatStrings(bucketHandle, string, close);
Toy_freeString(string);
string = tmp;
//clean up
Toy_freeString(open);
Toy_freeString(close);
Toy_freeString(comma); //TODO: reusable global, or string type "permanent"
return string;
}
case TOY_VALUE_TABLE: {
//TODO: concat + free is definitely a performance nightmare, could make an append function?
Toy_Table* ptr = value.as.table;
//if table is empty, skip below
if (ptr->count == 0) {
Toy_String* empty = Toy_createString(bucketHandle, "[:]");
return empty;
}
Toy_String* open = Toy_createStringLength(bucketHandle, "[", 1);
Toy_String* close = Toy_createStringLength(bucketHandle, "]", 1);
Toy_String* colon = Toy_createStringLength(bucketHandle, ":", 1); //reusable
Toy_String* comma = Toy_createStringLength(bucketHandle, ",", 1); //reusable
bool needsComma = false;
Toy_String* string = open;
for (unsigned int i = 0; i < ptr->capacity; i++) {
if (TOY_VALUE_IS_NULL(ptr->data[i].key)) {
continue;
}
if (needsComma) {
Toy_String* tmp = Toy_concatStrings(bucketHandle, string, comma); //increment ref
Toy_freeString(string); //decrement ref
string = tmp;
}
//make the element pair
Toy_String* k = Toy_stringifyValue(bucketHandle, ptr->data[i].key);
Toy_String* v = Toy_stringifyValue(bucketHandle, ptr->data[i].value);
Toy_String* c = Toy_concatStrings(bucketHandle, k, colon); //stick the colon between
Toy_String* pair = Toy_concatStrings(bucketHandle, c, v);
//append the element pair
Toy_String* final = Toy_concatStrings(bucketHandle, string, pair);
//do a bunch of freeing so the internal refCounts stay balanced
Toy_freeString(k);
Toy_freeString(v);
Toy_freeString(c);
Toy_freeString(pair);
Toy_freeString(string);
//finally
string = final;
//TODO: would a simple buffer be faster here?
//if there's more elements
needsComma = true;
}
//closing bracket
Toy_String* tmp = Toy_concatStrings(bucketHandle, string, close);
Toy_freeString(string);
string = tmp;
//clean up
Toy_freeString(open);
Toy_freeString(close);
Toy_freeString(colon); //TODO: reusable global, or string type "permanent"
Toy_freeString(comma); //TODO: reusable global, or string type "permanent"
return string;
}
case TOY_VALUE_TABLE:
case TOY_VALUE_FUNCTION:
case TOY_VALUE_OPAQUE:
case TOY_VALUE_TYPE:

View File

@@ -7,6 +7,7 @@
struct Toy_Bucket;
union Toy_String_t;
struct Toy_Array;
struct Toy_Table;
typedef enum Toy_ValueType {
TOY_VALUE_NULL,
@@ -34,6 +35,7 @@ typedef struct Toy_Value { //32 | 64 BITNESS
float number; //4 | 4
union Toy_String_t* string; //4 | 8
struct Toy_Array* array; //4 | 8
struct Toy_Table* table; //4 | 8
//TODO: more types go here
//TODO: consider 'stack' as a possible addition
@@ -59,6 +61,7 @@ typedef struct Toy_Value { //32 | 64 BITNESS
#define TOY_VALUE_AS_FLOAT(value) (Toy_unwrapValue(value).as.number)
#define TOY_VALUE_AS_STRING(value) (Toy_unwrapValue(value).as.string)
#define TOY_VALUE_AS_ARRAY(value) (Toy_unwrapValue(value).as.array)
#define TOY_VALUE_AS_TABLE(value) (Toy_unwrapValue(value).as.table)
//TODO: more
#define TOY_VALUE_FROM_NULL() ((Toy_Value){{ .integer = 0 }, TOY_VALUE_NULL})
@@ -67,6 +70,7 @@ typedef struct Toy_Value { //32 | 64 BITNESS
#define TOY_VALUE_FROM_FLOAT(value) ((Toy_Value){{ .number = value }, TOY_VALUE_FLOAT})
#define TOY_VALUE_FROM_STRING(value) ((Toy_Value){{ .string = value }, TOY_VALUE_STRING})
#define TOY_VALUE_FROM_ARRAY(value) ((Toy_Value){{ .array = value }, TOY_VALUE_ARRAY})
#define TOY_VALUE_FROM_TABLE(value) ((Toy_Value){{ .table = value }, TOY_VALUE_TABLE})
//TODO: more
#define TOY_REFERENCE_FROM_POINTER(ptr) ((Toy_Value){{ .reference = ptr }, TOY_VALUE_REFERENCE})

View File

@@ -119,8 +119,39 @@ static void processRead(Toy_VM* vm) {
}
case TOY_VALUE_TABLE: {
//
// break;
fixAlignment(vm);
//the number of values to read from the stack
unsigned int count = (unsigned int)READ_INT(vm);
//capacity covers keys AND values
unsigned int capacity = count / 2;
capacity = capacity > TOY_TABLE_INITIAL_CAPACITY ? capacity : TOY_TABLE_INITIAL_CAPACITY;
//neat trick to find the next power of two, inclusive (restriction of the table system) TODO: move this into a function
capacity--;
capacity |= capacity >> 1;
capacity |= capacity >> 2;
capacity |= capacity >> 4;
capacity |= capacity >> 8;
capacity |= capacity >> 16;
capacity++;
//create the table and read in the key-values
Toy_Table* table = Toy_private_adjustTableCapacity(NULL, capacity);
//read in backwards from the stack
for (unsigned int i = 0; i < count / 2; i++) {
Toy_Value v = Toy_popStack(&vm->stack);
Toy_Value k = Toy_popStack(&vm->stack);
Toy_insertTable(&table, k, v);
}
//finished
value = TOY_VALUE_FROM_TABLE(table);
break;
}
case TOY_VALUE_FUNCTION: {
@@ -214,6 +245,9 @@ static void processAssignCompound(Toy_VM* vm) {
if (TOY_VALUE_IS_STRING(target) && TOY_VALUE_AS_STRING(target)->info.type == TOY_STRING_NAME) {
Toy_Value* valuePtr = Toy_accessScopeAsPointer(vm->scope, TOY_VALUE_AS_STRING(target));
Toy_freeValue(target);
if (valuePtr == NULL) {
return;
}
target = TOY_REFERENCE_FROM_POINTER(valuePtr);
}
@@ -245,6 +279,16 @@ static void processAssignCompound(Toy_VM* vm) {
Toy_freeValue(value);
}
else if (TOY_VALUE_IS_TABLE(target)) {
Toy_Table* table = TOY_VALUE_AS_TABLE(target);
//set the value
Toy_insertTable(&table, key, Toy_copyValue(Toy_unwrapValue(value)));
//cleanup
Toy_freeValue(value);
}
else {
Toy_error("Invalid assignment target");
Toy_freeValue(target);
@@ -266,11 +310,15 @@ static void processAccess(Toy_VM* vm) {
//find the value
Toy_Value* valuePtr = Toy_accessScopeAsPointer(vm->scope, TOY_VALUE_AS_STRING(name));
//in the event of a certain subset of types, create references instead (these should only exist on the stack)
if (TOY_VALUE_IS_REFERENCE(*valuePtr) || TOY_VALUE_IS_ARRAY(*valuePtr)) {
//TODO: more types to be implemented
Toy_Value ref = TOY_REFERENCE_FROM_POINTER(valuePtr);
if (valuePtr == NULL) {
Toy_freeValue(name);
return;
}
//in the event of a certain subset of types, create references instead (these should only exist on the stack)
if (TOY_VALUE_IS_REFERENCE(*valuePtr) || TOY_VALUE_IS_ARRAY(*valuePtr) || TOY_VALUE_IS_TABLE(*valuePtr)) {
//TODO: more types to be implemented as stack-only references
Toy_Value ref = TOY_REFERENCE_FROM_POINTER(valuePtr);
Toy_pushStack(&vm->stack, ref);
}
@@ -649,7 +697,7 @@ static void processIndex(Toy_VM* vm) {
else if (TOY_VALUE_IS_ARRAY(value)) {
//type checks
if (!TOY_VALUE_IS_INTEGER(index)) {
Toy_error("Failed to index a string");
Toy_error("Failed to index an array");
Toy_freeValue(value);
Toy_freeValue(index);
Toy_freeValue(length);
@@ -657,7 +705,7 @@ static void processIndex(Toy_VM* vm) {
}
if (!(TOY_VALUE_IS_NULL(length) || TOY_VALUE_IS_INTEGER(length))) {
Toy_error("Failed to index-length a string");
Toy_error("Failed to index-length an array");
Toy_freeValue(value);
Toy_freeValue(index);
Toy_freeValue(length);
@@ -679,10 +727,9 @@ static void processIndex(Toy_VM* vm) {
}
//in the event of a certain subset of types, create references instead (these should only exist on the stack)
if (TOY_VALUE_IS_REFERENCE(array->data[i]) || TOY_VALUE_IS_ARRAY(array->data[i])) {
//TODO: more types to be implemented
if (TOY_VALUE_IS_REFERENCE(array->data[i]) || TOY_VALUE_IS_ARRAY(array->data[i]) || TOY_VALUE_IS_TABLE(array->data[i])) {
//TODO: more types to be implemented as stack-only references
Toy_Value ref = TOY_REFERENCE_FROM_POINTER(&(array->data[i]));
Toy_pushStack(&vm->stack, ref);
}
@@ -691,6 +738,31 @@ static void processIndex(Toy_VM* vm) {
}
}
else if (TOY_VALUE_IS_TABLE(value)) {
if (TOY_VALUE_IS_NULL(length) != true) {
Toy_error("Can't index-length a table");
Toy_freeValue(value);
Toy_freeValue(index);
Toy_freeValue(length);
return;
}
//get the table & element value
Toy_Table* table = TOY_VALUE_AS_TABLE(value);
Toy_TableEntry* entry = Toy_private_lookupTableEntryPtr(&table, index);
//in the event of a certain subset of types, create references instead (these should only exist on the stack)
if (TOY_VALUE_IS_REFERENCE(entry->value) || TOY_VALUE_IS_ARRAY(entry->value) || TOY_VALUE_IS_TABLE(entry->value)) {
//TODO: more types to be implemented as stack-only references
Toy_Value ref = TOY_REFERENCE_FROM_POINTER(&(entry->value));
Toy_pushStack(&vm->stack, ref);
}
else {
Toy_pushStack(&vm->stack, Toy_copyValue(entry->value));
}
}
else {
fprintf(stderr, TOY_CC_ERROR "ERROR: Unknown value type '%s' found in processIndex, exiting\n" TOY_CC_RESET, Toy_private_getValueTypeAsCString(value.type));
exit(-1);