mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 14:54:07 +10:00
Compound assignment for arrays is working, untested, read more
I added reference values in 62ca7a1fb7,
but forgot to mention it. I'm now using references to assign to the
internals of an array, no matter how many levels deep it is.
This commit is contained in:
19
scripts/compound.toy
Normal file
19
scripts/compound.toy
Normal file
@@ -0,0 +1,19 @@
|
||||
|
||||
|
||||
//1-D array
|
||||
var arr = [1, 2, 3];
|
||||
arr[1] = 6;
|
||||
print arr;
|
||||
|
||||
|
||||
|
||||
//we need to go deeper
|
||||
var barr = [
|
||||
[1, 2, 3],
|
||||
[4, 5, 6],
|
||||
[7, 8, 9]
|
||||
];
|
||||
|
||||
barr[1][1] = 99;
|
||||
|
||||
print barr;
|
||||
@@ -41,4 +41,5 @@ TOY_API Toy_Array* Toy_resizeArray(Toy_Array* array, unsigned int capacity);
|
||||
#define TOY_ARRAY_PUSHBACK(array, value) (TOY_ARRAY_EXPAND(array),(array)->data[(array)->count++] = (value))
|
||||
#endif
|
||||
|
||||
//URGENT: check array length from scripts
|
||||
//URGENT: get array length in scripts (dot operator?)
|
||||
//URGENT: array as a type
|
||||
@@ -1,12 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
typedef enum Toy_OpcodeType {
|
||||
//This offsets the opcode values, so I can see TOY_OPCODE_READ in GDB clearly
|
||||
TOY_OPCODE_UNUSED = 0,
|
||||
|
||||
//variable instructions
|
||||
TOY_OPCODE_READ,
|
||||
TOY_OPCODE_DECLARE,
|
||||
TOY_OPCODE_ASSIGN,
|
||||
TOY_OPCODE_ASSIGN_COMPOUND, //assign to a compound's internals
|
||||
TOY_OPCODE_ACCESS,
|
||||
|
||||
TOY_OPCODE_DUPLICATE, //duplicate the top of the stack
|
||||
|
||||
//arithmetic instructions
|
||||
|
||||
@@ -567,8 +567,7 @@ static Toy_AstFlag group(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast*
|
||||
}
|
||||
|
||||
static Toy_AstFlag compound(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {
|
||||
//read in an array or dictionary aggregate
|
||||
|
||||
//read in an array or dictionary compound definition
|
||||
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 compound expression");
|
||||
@@ -589,6 +588,7 @@ static Toy_AstFlag aggregate(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_
|
||||
//infix must advance
|
||||
advance(parser);
|
||||
|
||||
//aggregates are a collection of parts, expressing a larger idea
|
||||
if (parser->previous.type == TOY_TOKEN_OPERATOR_COMMA) {
|
||||
parsePrecedence(bucketHandle, parser, rootHandle, PREC_GROUP); //NOT +1, as compounds are right-recursive
|
||||
return TOY_AST_FLAG_COLLECTION;
|
||||
|
||||
@@ -453,8 +453,6 @@ static unsigned int writeInstructionVarDeclare(Toy_Routine** rt, Toy_AstVarDecla
|
||||
static unsigned int writeInstructionAssign(Toy_Routine** rt, Toy_AstVarAssign ast) {
|
||||
unsigned int result = 0;
|
||||
|
||||
//URGENT: check for LHS in index
|
||||
|
||||
//don't treat these as valid values
|
||||
switch (ast.expr->type) {
|
||||
case TOY_AST_BLOCK:
|
||||
@@ -463,7 +461,7 @@ static unsigned int writeInstructionAssign(Toy_Routine** rt, Toy_AstVarAssign as
|
||||
case TOY_AST_PRINT:
|
||||
case TOY_AST_VAR_DECLARE:
|
||||
//emit a compiler error, set the panic flag and skip out
|
||||
fprintf(stderr, TOY_CC_ERROR "COMPILER ERROR: Invalid AST type found: Malformed assignment\n" TOY_CC_RESET);
|
||||
fprintf(stderr, TOY_CC_ERROR "COMPILER ERROR: Invalid AST type found: Malformed assignment value\n" TOY_CC_RESET);
|
||||
(*rt)->panic = true;
|
||||
return 0;
|
||||
|
||||
@@ -471,7 +469,7 @@ static unsigned int writeInstructionAssign(Toy_Routine** rt, Toy_AstVarAssign as
|
||||
break;
|
||||
}
|
||||
|
||||
//target, based on type
|
||||
//target is a name string
|
||||
if (ast.target->type == TOY_AST_VALUE && TOY_VALUE_IS_STRING(ast.target->value.value) && TOY_VALUE_AS_STRING(ast.target->value.value)->type == TOY_STRING_NAME) {
|
||||
//name string
|
||||
Toy_String* target = TOY_VALUE_AS_STRING(ast.target->value.value);
|
||||
@@ -484,9 +482,24 @@ static unsigned int writeInstructionAssign(Toy_Routine** rt, Toy_AstVarAssign as
|
||||
|
||||
emitString(rt, target);
|
||||
}
|
||||
|
||||
//target is an indexing of some compound value
|
||||
else if (ast.target->type == TOY_AST_AGGREGATE && ast.target->aggregate.flag == TOY_AST_FLAG_INDEX) {
|
||||
writeRoutineCode(rt, ast.target->aggregate.left); //any deeper indexing will just work, using reference values
|
||||
writeRoutineCode(rt, ast.target->aggregate.right); //key
|
||||
writeRoutineCode(rt, ast.expr); //value
|
||||
|
||||
EMIT_BYTE(rt, code, TOY_OPCODE_ASSIGN_COMPOUND); //uses the top three values on the stack
|
||||
EMIT_BYTE(rt, code,0);
|
||||
EMIT_BYTE(rt, code,0);
|
||||
EMIT_BYTE(rt, code,0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
else {
|
||||
//URGENT: assigning to an array member
|
||||
fprintf(stderr, TOY_CC_ERROR "COMPILER ERROR: TODO at %s %d\n" TOY_CC_RESET, __FILE__, __LINE__);
|
||||
//unknown target
|
||||
fprintf(stderr, TOY_CC_ERROR "COMPILER ERROR: Invalid AST type found: Malformed assignment target\n" TOY_CC_RESET);
|
||||
(*rt)->panic = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
|
||||
#include "toy_print.h"
|
||||
|
||||
//URGENT: don't let references get saved into a scope
|
||||
|
||||
//utils
|
||||
static void incrementRefCount(Toy_Scope* scope) {
|
||||
for (Toy_Scope* iter = scope; iter; iter = iter->next) {
|
||||
@@ -110,9 +108,9 @@ void Toy_declareScope(Toy_Scope* scope, Toy_String* key, Toy_Value value) {
|
||||
|
||||
//type check
|
||||
Toy_ValueType kt = Toy_getNameStringType(key);
|
||||
if (kt != TOY_VALUE_ANY && value.type != TOY_VALUE_NULL && kt != value.type) {
|
||||
if (kt != TOY_VALUE_ANY && value.type != TOY_VALUE_NULL && kt != value.type && value.type != TOY_VALUE_REFERENCE) {
|
||||
char buffer[key->length + 256];
|
||||
sprintf(buffer, "Incorrect value type assigned to in variable declaration '%s' (expected %d, got %d)", key->as.name.data, (int)kt, (int)value.type);
|
||||
sprintf(buffer, "Incorrect value type in declaration of '%s' (expected %s, got %s)", key->as.name.data, Toy_private_getValueTypeAsCString(kt), Toy_private_getValueTypeAsCString(value.type));
|
||||
Toy_error(buffer);
|
||||
return;
|
||||
}
|
||||
@@ -147,9 +145,9 @@ void Toy_assignScope(Toy_Scope* scope, Toy_String* key, Toy_Value value) {
|
||||
|
||||
//type check
|
||||
Toy_ValueType kt = Toy_getNameStringType( TOY_VALUE_AS_STRING(entryPtr->key) );
|
||||
if (kt != TOY_VALUE_ANY && value.type != TOY_VALUE_NULL && kt != value.type) {
|
||||
if (kt != TOY_VALUE_ANY && value.type != TOY_VALUE_NULL && kt != value.type && value.type != TOY_VALUE_REFERENCE) {
|
||||
char buffer[key->length + 256];
|
||||
sprintf(buffer, "Incorrect value type assigned to in variable assignment '%s' (expected %d, got %d)", key->as.name.data, (int)kt, (int)value.type);
|
||||
sprintf(buffer, "Incorrect value type in assignment of '%s' (expected %s, got %s)", key->as.name.data, Toy_private_getValueTypeAsCString(kt), Toy_private_getValueTypeAsCString(value.type));
|
||||
Toy_error(buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -195,18 +195,68 @@ static void processAssign(Toy_VM* vm) {
|
||||
//check name string type
|
||||
if (!TOY_VALUE_IS_STRING(name) || TOY_VALUE_AS_STRING(name)->type != TOY_STRING_NAME) {
|
||||
Toy_error("Invalid assignment target");
|
||||
Toy_freeValue(name);
|
||||
Toy_freeValue(value);
|
||||
return;
|
||||
}
|
||||
|
||||
//assign it
|
||||
Toy_assignScope(vm->scope, TOY_VALUE_AS_STRING(name), value);
|
||||
|
||||
//URGENT: complex assignments
|
||||
Toy_assignScope(vm->scope, TOY_VALUE_AS_STRING(name), value); //scope now owns value, doesn't need to be freed
|
||||
|
||||
//cleanup
|
||||
Toy_freeValue(name);
|
||||
}
|
||||
|
||||
static void processAssignCompound(Toy_VM* vm) {
|
||||
//get the value, key, target
|
||||
Toy_Value value = Toy_popStack(&vm->stack);
|
||||
Toy_Value key = Toy_popStack(&vm->stack);
|
||||
Toy_Value target = Toy_popStack(&vm->stack);
|
||||
|
||||
//shake out variable names
|
||||
if (TOY_VALUE_IS_STRING(target) && TOY_VALUE_AS_STRING(target)->type == TOY_STRING_NAME) {
|
||||
Toy_Value* valuePtr = Toy_accessScopeAsPointer(vm->scope, TOY_VALUE_AS_STRING(target));
|
||||
Toy_freeValue(target);
|
||||
target = TOY_REFERENCE_FROM_POINTER(valuePtr);
|
||||
}
|
||||
|
||||
//assign based on target's type
|
||||
if (TOY_VALUE_IS_ARRAY(target)) {
|
||||
if (TOY_VALUE_IS_INTEGER(key) != true) {
|
||||
Toy_error("Bad key type for assignment target");
|
||||
Toy_freeValue(target);
|
||||
Toy_freeValue(key);
|
||||
Toy_freeValue(value);
|
||||
return;
|
||||
}
|
||||
|
||||
Toy_Array* array = TOY_VALUE_AS_ARRAY(target);
|
||||
int index = TOY_VALUE_AS_INTEGER(key);
|
||||
|
||||
//bounds check
|
||||
if (index < 0 || index >= array->count) {
|
||||
Toy_error("Index of assignment target out of bounds");
|
||||
Toy_freeValue(target);
|
||||
Toy_freeValue(key);
|
||||
Toy_freeValue(value);
|
||||
}
|
||||
|
||||
//set the value
|
||||
array->data[index] = Toy_copyValue(Toy_unwrapValue(value));
|
||||
|
||||
//cleanup
|
||||
Toy_freeValue(value);
|
||||
}
|
||||
|
||||
else {
|
||||
Toy_error("Invalid assignment target");
|
||||
Toy_freeValue(target);
|
||||
Toy_freeValue(key);
|
||||
Toy_freeValue(value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void processAccess(Toy_VM* vm) {
|
||||
Toy_Value name = Toy_popStack(&vm->stack);
|
||||
|
||||
@@ -760,6 +810,10 @@ static void process(Toy_VM* vm) {
|
||||
processAssign(vm);
|
||||
break;
|
||||
|
||||
case TOY_OPCODE_ASSIGN_COMPOUND:
|
||||
processAssignCompound(vm);
|
||||
break;
|
||||
|
||||
case TOY_OPCODE_ACCESS:
|
||||
processAccess(vm);
|
||||
break;
|
||||
@@ -828,6 +882,7 @@ static void process(Toy_VM* vm) {
|
||||
processIndex(vm);
|
||||
break;
|
||||
|
||||
case TOY_OPCODE_UNUSED:
|
||||
case TOY_OPCODE_PASS:
|
||||
case TOY_OPCODE_ERROR:
|
||||
case TOY_OPCODE_EOF:
|
||||
|
||||
Reference in New Issue
Block a user