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))
|
#define TOY_ARRAY_PUSHBACK(array, value) (TOY_ARRAY_EXPAND(array),(array)->data[(array)->count++] = (value))
|
||||||
#endif
|
#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
|
#pragma once
|
||||||
|
|
||||||
typedef enum Toy_OpcodeType {
|
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
|
//variable instructions
|
||||||
TOY_OPCODE_READ,
|
TOY_OPCODE_READ,
|
||||||
TOY_OPCODE_DECLARE,
|
TOY_OPCODE_DECLARE,
|
||||||
TOY_OPCODE_ASSIGN,
|
TOY_OPCODE_ASSIGN,
|
||||||
|
TOY_OPCODE_ASSIGN_COMPOUND, //assign to a compound's internals
|
||||||
TOY_OPCODE_ACCESS,
|
TOY_OPCODE_ACCESS,
|
||||||
|
|
||||||
TOY_OPCODE_DUPLICATE, //duplicate the top of the stack
|
TOY_OPCODE_DUPLICATE, //duplicate the top of the stack
|
||||||
|
|
||||||
//arithmetic instructions
|
//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) {
|
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) {
|
if (parser->previous.type == TOY_TOKEN_OPERATOR_BRACKET_LEFT) {
|
||||||
parsePrecedence(bucketHandle, parser, rootHandle, PREC_GROUP);
|
parsePrecedence(bucketHandle, parser, rootHandle, PREC_GROUP);
|
||||||
consume(parser, TOY_TOKEN_OPERATOR_BRACKET_RIGHT, "Expected ']' at the end of compound expression");
|
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
|
//infix must advance
|
||||||
advance(parser);
|
advance(parser);
|
||||||
|
|
||||||
|
//aggregates are a collection of parts, expressing a larger idea
|
||||||
if (parser->previous.type == TOY_TOKEN_OPERATOR_COMMA) {
|
if (parser->previous.type == TOY_TOKEN_OPERATOR_COMMA) {
|
||||||
parsePrecedence(bucketHandle, parser, rootHandle, PREC_GROUP); //NOT +1, as compounds are right-recursive
|
parsePrecedence(bucketHandle, parser, rootHandle, PREC_GROUP); //NOT +1, as compounds are right-recursive
|
||||||
return TOY_AST_FLAG_COLLECTION;
|
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) {
|
static unsigned int writeInstructionAssign(Toy_Routine** rt, Toy_AstVarAssign ast) {
|
||||||
unsigned int result = 0;
|
unsigned int result = 0;
|
||||||
|
|
||||||
//URGENT: check for LHS in index
|
|
||||||
|
|
||||||
//don't treat these as valid values
|
//don't treat these as valid values
|
||||||
switch (ast.expr->type) {
|
switch (ast.expr->type) {
|
||||||
case TOY_AST_BLOCK:
|
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_PRINT:
|
||||||
case TOY_AST_VAR_DECLARE:
|
case TOY_AST_VAR_DECLARE:
|
||||||
//emit a compiler error, set the panic flag and skip out
|
//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;
|
(*rt)->panic = true;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -471,7 +469,7 @@ static unsigned int writeInstructionAssign(Toy_Routine** rt, Toy_AstVarAssign as
|
|||||||
break;
|
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) {
|
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
|
//name string
|
||||||
Toy_String* target = TOY_VALUE_AS_STRING(ast.target->value.value);
|
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);
|
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 {
|
else {
|
||||||
//URGENT: assigning to an array member
|
//unknown target
|
||||||
fprintf(stderr, TOY_CC_ERROR "COMPILER ERROR: TODO at %s %d\n" TOY_CC_RESET, __FILE__, __LINE__);
|
fprintf(stderr, TOY_CC_ERROR "COMPILER ERROR: Invalid AST type found: Malformed assignment target\n" TOY_CC_RESET);
|
||||||
(*rt)->panic = true;
|
(*rt)->panic = true;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,6 @@
|
|||||||
|
|
||||||
#include "toy_print.h"
|
#include "toy_print.h"
|
||||||
|
|
||||||
//URGENT: don't let references get saved into a scope
|
|
||||||
|
|
||||||
//utils
|
//utils
|
||||||
static void incrementRefCount(Toy_Scope* scope) {
|
static void incrementRefCount(Toy_Scope* scope) {
|
||||||
for (Toy_Scope* iter = scope; iter; iter = iter->next) {
|
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
|
//type check
|
||||||
Toy_ValueType kt = Toy_getNameStringType(key);
|
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];
|
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);
|
Toy_error(buffer);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -147,9 +145,9 @@ void Toy_assignScope(Toy_Scope* scope, Toy_String* key, Toy_Value value) {
|
|||||||
|
|
||||||
//type check
|
//type check
|
||||||
Toy_ValueType kt = Toy_getNameStringType( TOY_VALUE_AS_STRING(entryPtr->key) );
|
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];
|
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);
|
Toy_error(buffer);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -195,18 +195,68 @@ static void processAssign(Toy_VM* vm) {
|
|||||||
//check name string type
|
//check name string type
|
||||||
if (!TOY_VALUE_IS_STRING(name) || TOY_VALUE_AS_STRING(name)->type != TOY_STRING_NAME) {
|
if (!TOY_VALUE_IS_STRING(name) || TOY_VALUE_AS_STRING(name)->type != TOY_STRING_NAME) {
|
||||||
Toy_error("Invalid assignment target");
|
Toy_error("Invalid assignment target");
|
||||||
|
Toy_freeValue(name);
|
||||||
|
Toy_freeValue(value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//assign it
|
//assign it
|
||||||
Toy_assignScope(vm->scope, TOY_VALUE_AS_STRING(name), value);
|
Toy_assignScope(vm->scope, TOY_VALUE_AS_STRING(name), value); //scope now owns value, doesn't need to be freed
|
||||||
|
|
||||||
//URGENT: complex assignments
|
|
||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
Toy_freeValue(name);
|
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) {
|
static void processAccess(Toy_VM* vm) {
|
||||||
Toy_Value name = Toy_popStack(&vm->stack);
|
Toy_Value name = Toy_popStack(&vm->stack);
|
||||||
|
|
||||||
@@ -760,6 +810,10 @@ static void process(Toy_VM* vm) {
|
|||||||
processAssign(vm);
|
processAssign(vm);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TOY_OPCODE_ASSIGN_COMPOUND:
|
||||||
|
processAssignCompound(vm);
|
||||||
|
break;
|
||||||
|
|
||||||
case TOY_OPCODE_ACCESS:
|
case TOY_OPCODE_ACCESS:
|
||||||
processAccess(vm);
|
processAccess(vm);
|
||||||
break;
|
break;
|
||||||
@@ -828,6 +882,7 @@ static void process(Toy_VM* vm) {
|
|||||||
processIndex(vm);
|
processIndex(vm);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TOY_OPCODE_UNUSED:
|
||||||
case TOY_OPCODE_PASS:
|
case TOY_OPCODE_PASS:
|
||||||
case TOY_OPCODE_ERROR:
|
case TOY_OPCODE_ERROR:
|
||||||
case TOY_OPCODE_EOF:
|
case TOY_OPCODE_EOF:
|
||||||
|
|||||||
Reference in New Issue
Block a user