Files
Toy/source/toy_builtin.c
Kayne Ruse 1dde9d8f29 Improved error message in set() and push()
The actual issue was that the type check wasn't catching the issue, so
it reached the scope before it was caught. Fixed it, anyway.
2023-02-20 13:04:35 +00:00

1594 lines
43 KiB
C

#include "toy_builtin.h"
#include "toy_memory.h"
#include "toy_literal.h"
#include <stdio.h>
#include <string.h>
//static math utils, copied from the interpreter
static Toy_Literal addition(Toy_Interpreter* interpreter, Toy_Literal lhs, Toy_Literal rhs) {
//special case for string concatenation ONLY
if (TOY_IS_STRING(lhs) && TOY_IS_STRING(rhs)) {
//check for overflow
int totalLength = TOY_AS_STRING(lhs)->length + TOY_AS_STRING(rhs)->length;
if (totalLength > TOY_MAX_STRING_LENGTH) {
interpreter->errorOutput("Can't concatenate these strings (result is too long)\n");
return TOY_TO_NULL_LITERAL;
}
//concat the strings
char buffer[TOY_MAX_STRING_LENGTH];
snprintf(buffer, TOY_MAX_STRING_LENGTH, "%s%s", Toy_toCString(TOY_AS_STRING(lhs)), Toy_toCString(TOY_AS_STRING(rhs)));
Toy_Literal literal = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(buffer, totalLength));
Toy_freeLiteral(lhs);
Toy_freeLiteral(rhs);
return literal;
}
//type coersion
if (TOY_IS_FLOAT(lhs) && TOY_IS_INTEGER(rhs)) {
rhs = TOY_TO_FLOAT_LITERAL(TOY_AS_INTEGER(rhs));
}
if (TOY_IS_INTEGER(lhs) && TOY_IS_FLOAT(rhs)) {
lhs = TOY_TO_FLOAT_LITERAL(TOY_AS_INTEGER(lhs));
}
//results
Toy_Literal result = TOY_TO_NULL_LITERAL;
if (TOY_IS_INTEGER(lhs) && TOY_IS_INTEGER(rhs)) {
result = TOY_TO_INTEGER_LITERAL( TOY_AS_INTEGER(lhs) + TOY_AS_INTEGER(rhs) );
Toy_freeLiteral(lhs);
Toy_freeLiteral(rhs);
return result;
}
if (TOY_IS_FLOAT(lhs) && TOY_IS_FLOAT(rhs)) {
result = TOY_TO_FLOAT_LITERAL( TOY_AS_FLOAT(lhs) + TOY_AS_FLOAT(rhs) );
Toy_freeLiteral(lhs);
Toy_freeLiteral(rhs);
return result;
}
//wrong types
interpreter->errorOutput("Bad arithmetic argument ");
Toy_printLiteralCustom(lhs, interpreter->errorOutput);
interpreter->errorOutput(" and ");
Toy_printLiteralCustom(rhs, interpreter->errorOutput);
interpreter->errorOutput("\n");
Toy_freeLiteral(lhs);
Toy_freeLiteral(rhs);
return TOY_TO_NULL_LITERAL;
}
static Toy_Literal subtraction(Toy_Interpreter* interpreter, Toy_Literal lhs, Toy_Literal rhs) {
//type coersion
if (TOY_IS_FLOAT(lhs) && TOY_IS_INTEGER(rhs)) {
rhs = TOY_TO_FLOAT_LITERAL(TOY_AS_INTEGER(rhs));
}
if (TOY_IS_INTEGER(lhs) && TOY_IS_FLOAT(rhs)) {
lhs = TOY_TO_FLOAT_LITERAL(TOY_AS_INTEGER(lhs));
}
//results
Toy_Literal result = TOY_TO_NULL_LITERAL;
if (TOY_IS_INTEGER(lhs) && TOY_IS_INTEGER(rhs)) {
result = TOY_TO_INTEGER_LITERAL( TOY_AS_INTEGER(lhs) - TOY_AS_INTEGER(rhs) );
Toy_freeLiteral(lhs);
Toy_freeLiteral(rhs);
return result;
}
if (TOY_IS_FLOAT(lhs) && TOY_IS_FLOAT(rhs)) {
result = TOY_TO_FLOAT_LITERAL( TOY_AS_FLOAT(lhs) - TOY_AS_FLOAT(rhs) );
Toy_freeLiteral(lhs);
Toy_freeLiteral(rhs);
return result;
}
//wrong types
interpreter->errorOutput("Bad arithmetic argument ");
Toy_printLiteralCustom(lhs, interpreter->errorOutput);
interpreter->errorOutput(" and ");
Toy_printLiteralCustom(rhs, interpreter->errorOutput);
interpreter->errorOutput("\n");
Toy_freeLiteral(lhs);
Toy_freeLiteral(rhs);
return TOY_TO_NULL_LITERAL;
}
static Toy_Literal multiplication(Toy_Interpreter* interpreter, Toy_Literal lhs, Toy_Literal rhs) {
//type coersion
if (TOY_IS_FLOAT(lhs) && TOY_IS_INTEGER(rhs)) {
rhs = TOY_TO_FLOAT_LITERAL(TOY_AS_INTEGER(rhs));
}
if (TOY_IS_INTEGER(lhs) && TOY_IS_FLOAT(rhs)) {
lhs = TOY_TO_FLOAT_LITERAL(TOY_AS_INTEGER(lhs));
}
//results
Toy_Literal result = TOY_TO_NULL_LITERAL;
if (TOY_IS_INTEGER(lhs) && TOY_IS_INTEGER(rhs)) {
result = TOY_TO_INTEGER_LITERAL( TOY_AS_INTEGER(lhs) * TOY_AS_INTEGER(rhs) );
Toy_freeLiteral(lhs);
Toy_freeLiteral(rhs);
return result;
}
if (TOY_IS_FLOAT(lhs) && TOY_IS_FLOAT(rhs)) {
result = TOY_TO_FLOAT_LITERAL( TOY_AS_FLOAT(lhs) * TOY_AS_FLOAT(rhs) );
Toy_freeLiteral(lhs);
Toy_freeLiteral(rhs);
return result;
}
//wrong types
interpreter->errorOutput("Bad arithmetic argument ");
Toy_printLiteralCustom(lhs, interpreter->errorOutput);
interpreter->errorOutput(" and ");
Toy_printLiteralCustom(rhs, interpreter->errorOutput);
interpreter->errorOutput("\n");
Toy_freeLiteral(lhs);
Toy_freeLiteral(rhs);
return TOY_TO_NULL_LITERAL;
}
static Toy_Literal division(Toy_Interpreter* interpreter, Toy_Literal lhs, Toy_Literal rhs) {
//division check
if ((TOY_IS_INTEGER(rhs) && TOY_AS_INTEGER(rhs) == 0) || (TOY_IS_FLOAT(rhs) && TOY_AS_FLOAT(rhs) == 0)) {
interpreter->errorOutput("Can't divide by zero");
}
//type coersion
if (TOY_IS_FLOAT(lhs) && TOY_IS_INTEGER(rhs)) {
rhs = TOY_TO_FLOAT_LITERAL(TOY_AS_INTEGER(rhs));
}
if (TOY_IS_INTEGER(lhs) && TOY_IS_FLOAT(rhs)) {
lhs = TOY_TO_FLOAT_LITERAL(TOY_AS_INTEGER(lhs));
}
//results
Toy_Literal result = TOY_TO_NULL_LITERAL;
if (TOY_IS_INTEGER(lhs) && TOY_IS_INTEGER(rhs)) {
result = TOY_TO_INTEGER_LITERAL( TOY_AS_INTEGER(lhs) + TOY_AS_INTEGER(rhs) );
Toy_freeLiteral(lhs);
Toy_freeLiteral(rhs);
return result;
}
if (TOY_IS_FLOAT(lhs) && TOY_IS_FLOAT(rhs)) {
result = TOY_TO_FLOAT_LITERAL( TOY_AS_FLOAT(lhs) + TOY_AS_FLOAT(rhs) );
Toy_freeLiteral(lhs);
Toy_freeLiteral(rhs);
return result;
}
//wrong types
interpreter->errorOutput("Bad arithmetic argument ");
Toy_printLiteralCustom(lhs, interpreter->errorOutput);
interpreter->errorOutput(" and ");
Toy_printLiteralCustom(rhs, interpreter->errorOutput);
interpreter->errorOutput("\n");
Toy_freeLiteral(lhs);
Toy_freeLiteral(rhs);
return TOY_TO_NULL_LITERAL;
}
static Toy_Literal modulo(Toy_Interpreter* interpreter, Toy_Literal lhs, Toy_Literal rhs) {
//division check
if ((TOY_IS_INTEGER(rhs) && TOY_AS_INTEGER(rhs) == 0) || (TOY_IS_FLOAT(rhs) && TOY_AS_FLOAT(rhs) == 0)) {
interpreter->errorOutput("Can't divide by zero");
}
//type coersion
if (TOY_IS_FLOAT(lhs) && TOY_IS_INTEGER(rhs)) {
rhs = TOY_TO_FLOAT_LITERAL(TOY_AS_INTEGER(rhs));
}
if (TOY_IS_INTEGER(lhs) && TOY_IS_FLOAT(rhs)) {
lhs = TOY_TO_FLOAT_LITERAL(TOY_AS_INTEGER(lhs));
}
//results
Toy_Literal result = TOY_TO_NULL_LITERAL;
if (TOY_IS_INTEGER(lhs) && TOY_IS_INTEGER(rhs)) {
result = TOY_TO_INTEGER_LITERAL( TOY_AS_INTEGER(lhs) + TOY_AS_INTEGER(rhs) );
Toy_freeLiteral(lhs);
Toy_freeLiteral(rhs);
return result;
}
//NOTE: no float modulo
//wrong types
interpreter->errorOutput("Bad arithmetic argument ");
Toy_printLiteralCustom(lhs, interpreter->errorOutput);
interpreter->errorOutput(" and ");
Toy_printLiteralCustom(rhs, interpreter->errorOutput);
interpreter->errorOutput("\n");
Toy_freeLiteral(lhs);
Toy_freeLiteral(rhs);
return TOY_TO_NULL_LITERAL;
}
int Toy_private_index(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//_index(compound, first, second, third, assignValue, op)
Toy_Literal op = Toy_popLiteralArray(arguments);
Toy_Literal assign = Toy_popLiteralArray(arguments);
Toy_Literal third = Toy_popLiteralArray(arguments);
Toy_Literal second = Toy_popLiteralArray(arguments);
Toy_Literal first = Toy_popLiteralArray(arguments);
Toy_Literal compound = Toy_popLiteralArray(arguments);
//dictionary - no slicing
if (TOY_IS_DICTIONARY(compound)) {
if (TOY_IS_IDENTIFIER(first)) {
Toy_Literal idn = first;
Toy_parseIdentifierToValue(interpreter, &first);
Toy_freeLiteral(idn);
}
if (TOY_IS_IDENTIFIER(second)) {
Toy_Literal idn = second;
Toy_parseIdentifierToValue(interpreter, &second);
Toy_freeLiteral(idn);
}
if (TOY_IS_IDENTIFIER(third)) {
Toy_Literal idn = third;
Toy_parseIdentifierToValue(interpreter, &third);
Toy_freeLiteral(idn);
}
if (TOY_IS_IDENTIFIER(first) || TOY_IS_IDENTIFIER(second) || TOY_IS_IDENTIFIER(third)) {
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return -1;
}
//second and third are bad args to dictionaries
if (!TOY_IS_NULL(second) || !TOY_IS_NULL(third)) {
interpreter->errorOutput("Index slicing not allowed for dictionaries\n");
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return -1;
}
//get the value
Toy_Literal value = Toy_getLiteralDictionary(TOY_AS_DICTIONARY(compound), first);
//dictionary
if (TOY_IS_NULL(op)) {
Toy_pushLiteralArray(&interpreter->stack, value);
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
Toy_freeLiteral(value);
return 1;
}
else if (Toy_equalsRefStringCString(TOY_AS_STRING(op), "=")) {
Toy_setLiteralDictionary(TOY_AS_DICTIONARY(compound), first, assign);
}
else if (Toy_equalsRefStringCString(TOY_AS_STRING(op), "+=")) {
Toy_Literal lit = addition(interpreter, value, assign);
Toy_setLiteralDictionary(TOY_AS_DICTIONARY(compound), first, lit);
Toy_freeLiteral(lit);
}
else if (Toy_equalsRefStringCString(TOY_AS_STRING(op), "-=")) {
Toy_Literal lit = subtraction(interpreter, value, assign);
Toy_setLiteralDictionary(TOY_AS_DICTIONARY(compound), first, lit);
Toy_freeLiteral(lit);
}
else if (Toy_equalsRefStringCString(TOY_AS_STRING(op), "*=")) {
Toy_Literal lit = multiplication(interpreter, value, assign);
Toy_setLiteralDictionary(TOY_AS_DICTIONARY(compound), first, lit);
Toy_freeLiteral(lit);
}
else if (Toy_equalsRefStringCString(TOY_AS_STRING(op), "/=")) {
Toy_Literal lit = division(interpreter, value, assign);
Toy_setLiteralDictionary(TOY_AS_DICTIONARY(compound), first, lit);
Toy_freeLiteral(lit);
}
else if (Toy_equalsRefStringCString(TOY_AS_STRING(op), "%=")) {
Toy_Literal lit = modulo(interpreter, value, assign);
Toy_setLiteralDictionary(TOY_AS_DICTIONARY(compound), first, lit);
Toy_freeLiteral(lit);
}
//leave the dictionary on the stack
Toy_pushLiteralArray(&interpreter->stack, compound);
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
Toy_freeLiteral(value);
return 1;
}
//array - slicing
if (TOY_IS_ARRAY(compound)) {
//array slice
if (TOY_IS_NULL(op)) {
//parse out the blanks & their defaults
if (!TOY_IS_NULL(first)) {
if (TOY_IS_INDEX_BLANK(first)) {
Toy_freeLiteral(first);
first = TOY_TO_INTEGER_LITERAL(0);
}
if (TOY_IS_IDENTIFIER(first)) {
Toy_Literal idn = first;
Toy_parseIdentifierToValue(interpreter, &first);
Toy_freeLiteral(idn);
}
}
if (!TOY_IS_NULL(second)) {
if (TOY_IS_INDEX_BLANK(second)) {
Toy_freeLiteral(second);
second = TOY_TO_INTEGER_LITERAL(TOY_AS_ARRAY(compound)->count - 1);
}
if (TOY_IS_IDENTIFIER(second)) {
Toy_Literal idn = second;
Toy_parseIdentifierToValue(interpreter, &second);
Toy_freeLiteral(idn);
}
}
if (TOY_IS_NULL(third) || TOY_IS_INDEX_BLANK(third)) {
Toy_freeLiteral(third);
third = TOY_TO_INTEGER_LITERAL(1);
}
if (TOY_IS_IDENTIFIER(third)) {
Toy_Literal idn = third;
Toy_parseIdentifierToValue(interpreter, &third);
Toy_freeLiteral(idn);
}
if (TOY_IS_IDENTIFIER(first) || TOY_IS_IDENTIFIER(second) || TOY_IS_IDENTIFIER(third)) {
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return -1;
}
//handle each error case
if (!TOY_IS_INTEGER(first) || TOY_AS_INTEGER(first) < 0 || TOY_AS_INTEGER(first) >= TOY_AS_ARRAY(compound)->count) {
interpreter->errorOutput("Bad first indexing\n");
//something is weird - skip out
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return -1;
}
if ((!TOY_IS_NULL(second) && !TOY_IS_INTEGER(second)) || TOY_AS_INTEGER(second) < 0 || TOY_AS_INTEGER(second) >= TOY_AS_ARRAY(compound)->count) {
interpreter->errorOutput("Bad second indexing\n");
//something is weird - skip out
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return -1;
}
if ((!TOY_IS_NULL(third) && !TOY_IS_INTEGER(third)) || TOY_AS_INTEGER(third) == 0) {
interpreter->errorOutput("Bad third indexing\n");
//something is weird - skip out
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return -1;
}
//simple indexing if second is null
if (TOY_IS_NULL(second)) {
Toy_Literal result = Toy_getLiteralArray(TOY_AS_ARRAY(compound), first);
Toy_pushLiteralArray(&interpreter->stack, result);
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
Toy_freeLiteral(result);
return 1;
}
//start building a new array from the old one
Toy_LiteralArray* result = TOY_ALLOCATE(Toy_LiteralArray, 1);
Toy_initLiteralArray(result);
//copy compound into result
if (TOY_AS_INTEGER(third) > 0) {
for (int i = TOY_AS_INTEGER(first); i <= TOY_AS_INTEGER(second); i += TOY_AS_INTEGER(third)) {
Toy_Literal idx = TOY_TO_INTEGER_LITERAL(i);
Toy_Literal tmp = Toy_getLiteralArray(TOY_AS_ARRAY(compound), idx);
Toy_pushLiteralArray(result, tmp);
Toy_freeLiteral(idx);
Toy_freeLiteral(tmp);
}
}
else {
for (int i = TOY_AS_INTEGER(second); i >= TOY_AS_INTEGER(first); i += TOY_AS_INTEGER(third)) {
Toy_Literal idx = TOY_TO_INTEGER_LITERAL(i);
Toy_Literal tmp = Toy_getLiteralArray(TOY_AS_ARRAY(compound), idx);
Toy_pushLiteralArray(result, tmp);
Toy_freeLiteral(idx);
Toy_freeLiteral(tmp);
}
}
//finally, swap out the compound for the result
Toy_freeLiteral(compound);
compound = TOY_TO_ARRAY_LITERAL(result);
//leave the array on the stack
Toy_pushLiteralArray(&interpreter->stack, compound);
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return 1;
}
//array slice assignment
if (TOY_IS_STRING(op) && Toy_equalsRefStringCString(TOY_AS_STRING(op), "=")) {
//parse out the blanks & their defaults
if (!TOY_IS_NULL(first)) {
if (TOY_IS_INDEX_BLANK(first)) {
Toy_freeLiteral(first);
first = TOY_TO_INTEGER_LITERAL(0);
}
if (TOY_IS_IDENTIFIER(first)) {
Toy_Literal idn = first;
Toy_parseIdentifierToValue(interpreter, &first);
Toy_freeLiteral(idn);
}
}
if (!TOY_IS_NULL(second)) {
if (TOY_IS_INDEX_BLANK(second)) {
Toy_freeLiteral(second);
second = TOY_TO_INTEGER_LITERAL(TOY_AS_INTEGER(first));
}
if (TOY_IS_IDENTIFIER(second)) {
Toy_Literal idn = second;
Toy_parseIdentifierToValue(interpreter, &second);
Toy_freeLiteral(idn);
}
}
if (TOY_IS_NULL(third) || TOY_IS_INDEX_BLANK(third)) {
Toy_freeLiteral(third);
third = TOY_TO_INTEGER_LITERAL(1);
}
if (TOY_IS_IDENTIFIER(third)) {
Toy_Literal idn = third;
Toy_parseIdentifierToValue(interpreter, &third);
Toy_freeLiteral(idn);
}
if (TOY_IS_IDENTIFIER(first) || TOY_IS_IDENTIFIER(second) || TOY_IS_IDENTIFIER(third)) {
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return -1;
}
//handle each error case
if (!TOY_IS_INTEGER(first) || TOY_AS_INTEGER(first) < 0 || TOY_AS_INTEGER(first) >= TOY_AS_ARRAY(compound)->count) {
interpreter->errorOutput("Bad first indexing assignment\n");
//something is weird - skip out
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return -1;
}
if ((!TOY_IS_NULL(second) && !TOY_IS_INTEGER(second)) || TOY_AS_INTEGER(second) < 0 || TOY_AS_INTEGER(second) >= TOY_AS_ARRAY(compound)->count) {
interpreter->errorOutput("Bad second indexing assignment\n");
//something is weird - skip out
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return -1;
}
if ((!TOY_IS_NULL(third) && !TOY_IS_INTEGER(third)) || TOY_AS_INTEGER(third) == 0) {
interpreter->errorOutput("Bad third indexing assignment\n");
//something is weird - skip out
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return -1;
}
//simple indexing assignment if second is null
if (TOY_IS_NULL(second)) {
bool ret = -1;
if (!Toy_setLiteralArray(TOY_AS_ARRAY(compound), first, assign)) {
interpreter->errorOutput("Array index out of bounds in assignment");
return -1;
}
else {
Toy_pushLiteralArray(&interpreter->stack, compound); //leave the array on the stack
ret = 1;
}
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return ret;
}
//start building a new array from the old one
Toy_LiteralArray* result = TOY_ALLOCATE(Toy_LiteralArray, 1);
Toy_initLiteralArray(result);
//if third is abs(1), simply insert into the correct positions
if (TOY_AS_INTEGER(third) == 1 || TOY_AS_INTEGER(third) == -1) {
for (int i = 0; i < TOY_AS_INTEGER(first); i++) {
Toy_Literal idx = TOY_TO_INTEGER_LITERAL(i);
Toy_Literal tmp = Toy_getLiteralArray(TOY_AS_ARRAY(compound), idx);
Toy_pushLiteralArray(result, tmp);
Toy_freeLiteral(idx);
Toy_freeLiteral(tmp);
}
int min = TOY_AS_INTEGER(third) > 0 ? 0 : TOY_AS_ARRAY(assign)->count - 1;
if (TOY_IS_ARRAY(assign)) { //push elements of an assigned array
for (int i = min; i >= 0 && i < TOY_AS_ARRAY(assign)->count; i += TOY_AS_INTEGER(third)) {
Toy_Literal idx = TOY_TO_INTEGER_LITERAL(i);
Toy_Literal tmp = Toy_getLiteralArray(TOY_AS_ARRAY(assign), idx); //backwards
//set result
Toy_pushLiteralArray(result, tmp);
Toy_freeLiteral(idx);
Toy_freeLiteral(tmp);
}
}
else { //push just one element into the array
Toy_pushLiteralArray(result, assign);
}
for (int i = TOY_AS_INTEGER(second) + 1; i < TOY_AS_ARRAY(compound)->count; i++) {
Toy_Literal idx = TOY_TO_INTEGER_LITERAL(i);
Toy_Literal tmp = Toy_getLiteralArray(TOY_AS_ARRAY(compound), idx);
Toy_pushLiteralArray(result, tmp);
Toy_freeLiteral(idx);
Toy_freeLiteral(tmp);
}
}
//else override elements of the array instead
else {
//copy compound to result
for (int i = 0; i < TOY_AS_ARRAY(compound)->count; i++) {
Toy_Literal idx = TOY_TO_INTEGER_LITERAL(i);
Toy_Literal tmp = Toy_getLiteralArray(TOY_AS_ARRAY(compound), idx);
Toy_pushLiteralArray(result, tmp);
Toy_freeLiteral(idx);
Toy_freeLiteral(tmp);
}
int min = TOY_AS_INTEGER(third) > 0 ? 0 : TOY_AS_ARRAY(compound)->count - 1;
int assignIndex = 0;
for (int i = min; i >= 0 && i < TOY_AS_ARRAY(compound)->count && assignIndex < TOY_AS_ARRAY(assign)->count; i += TOY_AS_INTEGER(third)) {
Toy_Literal idx = TOY_TO_INTEGER_LITERAL(i);
Toy_Literal ai = TOY_TO_INTEGER_LITERAL(assignIndex++);
Toy_Literal tmp = Toy_getLiteralArray(TOY_AS_ARRAY(assign), ai);
Toy_setLiteralArray(result, idx, tmp);
Toy_freeLiteral(idx);
Toy_freeLiteral(ai);
Toy_freeLiteral(tmp);
}
}
//finally, swap out the compound for the result
Toy_freeLiteral(compound);
compound = TOY_TO_ARRAY_LITERAL(result);
//leave the array on the stack
Toy_pushLiteralArray(&interpreter->stack, compound);
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return 1;
}
//assignment and other operations
if (TOY_IS_IDENTIFIER(first)) {
Toy_Literal idn = first;
Toy_parseIdentifierToValue(interpreter, &first);
Toy_freeLiteral(idn);
}
if (TOY_IS_IDENTIFIER(first)) {
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return -1;
}
Toy_Literal value = Toy_getLiteralArray(TOY_AS_ARRAY(compound), first);
if (TOY_IS_STRING(op) && Toy_equalsRefStringCString(TOY_AS_STRING(op), "+=")) {
Toy_Literal lit = addition(interpreter, value, assign);
Toy_setLiteralArray(TOY_AS_ARRAY(compound), first, lit);
Toy_freeLiteral(lit);
}
if (TOY_IS_STRING(op) && Toy_equalsRefStringCString(TOY_AS_STRING(op), "-=")) {
Toy_Literal lit = subtraction(interpreter, value, assign);
Toy_setLiteralArray(TOY_AS_ARRAY(compound), first, lit);
Toy_freeLiteral(lit);
}
if (TOY_IS_STRING(op) && Toy_equalsRefStringCString(TOY_AS_STRING(op), "*=")) {
Toy_Literal lit = multiplication(interpreter, value, assign);
Toy_setLiteralArray(TOY_AS_ARRAY(compound), first, lit);
Toy_freeLiteral(lit);
}
if (TOY_IS_STRING(op) && Toy_equalsRefStringCString(TOY_AS_STRING(op), "/=")) {
Toy_Literal lit = division(interpreter, value, assign);
Toy_setLiteralArray(TOY_AS_ARRAY(compound), first, lit);
Toy_freeLiteral(lit);
}
if (TOY_IS_STRING(op) && Toy_equalsRefStringCString(TOY_AS_STRING(op), "%=")) {
Toy_Literal lit = modulo(interpreter, value, assign);
Toy_setLiteralArray(TOY_AS_ARRAY(compound), first, lit);
Toy_freeLiteral(lit);
}
//leave the array on the stack
Toy_pushLiteralArray(&interpreter->stack, compound);
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return 1;
}
//string - slicing
if (TOY_IS_STRING(compound)) {
//string slice
if (TOY_IS_NULL(op)) {
//parse out the blanks & their defaults
if (!TOY_IS_NULL(first)) {
if (TOY_IS_INDEX_BLANK(first)) {
Toy_freeLiteral(first);
first = TOY_TO_INTEGER_LITERAL(0);
}
if (TOY_IS_IDENTIFIER(first)) {
Toy_Literal idn = first;
Toy_parseIdentifierToValue(interpreter, &first);
Toy_freeLiteral(idn);
}
}
int compoundLength = TOY_AS_STRING(compound)->length;
if (!TOY_IS_NULL(second)) {
if (TOY_IS_INDEX_BLANK(second)) {
Toy_freeLiteral(second);
second = TOY_TO_INTEGER_LITERAL(compoundLength - 1);
}
if (TOY_IS_IDENTIFIER(second)) {
Toy_Literal idn = second;
Toy_parseIdentifierToValue(interpreter, &second);
Toy_freeLiteral(idn);
}
}
if (TOY_IS_NULL(third) || TOY_IS_INDEX_BLANK(third)) {
Toy_freeLiteral(third);
third = TOY_TO_INTEGER_LITERAL(1);
}
if (TOY_IS_IDENTIFIER(third)) {
Toy_Literal idn = third;
Toy_parseIdentifierToValue(interpreter, &third);
Toy_freeLiteral(idn);
}
if (TOY_IS_IDENTIFIER(first) || TOY_IS_IDENTIFIER(second) || TOY_IS_IDENTIFIER(third)) {
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return -1;
}
//handle each error case
if (!TOY_IS_INTEGER(first) || TOY_AS_INTEGER(first) < 0 || TOY_AS_INTEGER(first) >= (int)Toy_lengthRefString(TOY_AS_STRING(compound))) {
interpreter->errorOutput("Bad first indexing in string\n");
//something is weird - skip out
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return -1;
}
if ((!TOY_IS_NULL(second) && !TOY_IS_INTEGER(second)) || TOY_AS_INTEGER(second) < 0 || TOY_AS_INTEGER(second) >= (int)Toy_lengthRefString(TOY_AS_STRING(compound))) {
interpreter->errorOutput("Bad second indexing in string\n");
//something is weird - skip out
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return -1;
}
if ((!TOY_IS_NULL(third) && !TOY_IS_INTEGER(third)) || TOY_AS_INTEGER(third) == 0) {
interpreter->errorOutput("Bad third indexing in string\n");
//something is weird - skip out
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return -1;
}
//simple indexing if second is null
if (TOY_IS_NULL(second)) {
const char* cstr = Toy_toCString(TOY_AS_STRING(compound));
char buf[16];
snprintf(buf, 16, "%s", &(cstr[ TOY_AS_INTEGER(first) ]) );
Toy_Literal result = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(buf, 1));
Toy_pushLiteralArray(&interpreter->stack, result);
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
Toy_freeLiteral(result);
return 1;
}
//start building a new string from the old one
char* result = TOY_ALLOCATE(char, TOY_MAX_STRING_LENGTH);
//copy compound into result
int resultIndex = 0;
if (TOY_AS_INTEGER(third) > 0) {
for (int i = TOY_AS_INTEGER(first); i <= TOY_AS_INTEGER(second); i += TOY_AS_INTEGER(third)) {
result[ resultIndex++ ] = Toy_toCString(TOY_AS_STRING(compound))[ i ];
}
}
else {
for (int i = TOY_AS_INTEGER(second); i >= TOY_AS_INTEGER(first); i += TOY_AS_INTEGER(third)) {
result[ resultIndex++ ] = Toy_toCString(TOY_AS_STRING(compound))[ i ];
}
}
result[ resultIndex ] = '\0';
//finally, swap out the compound for the result
Toy_freeLiteral(compound);
compound = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(result, resultIndex));
TOY_FREE_ARRAY(char, result, TOY_MAX_STRING_LENGTH);
//leave the string on the stack
Toy_pushLiteralArray(&interpreter->stack, compound);
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return 1;
}
//string slice assignment
else if (TOY_IS_STRING(op) && Toy_equalsRefStringCString(TOY_AS_STRING(op), "=")) {
//parse out the blanks & their defaults
if (!TOY_IS_NULL(first)) {
if (TOY_IS_INDEX_BLANK(first)) {
Toy_freeLiteral(first);
first = TOY_TO_INTEGER_LITERAL(0);
}
if (TOY_IS_IDENTIFIER(first)) {
Toy_Literal idn = first;
Toy_parseIdentifierToValue(interpreter, &first);
Toy_freeLiteral(idn);
}
}
int compoundLength = TOY_AS_STRING(compound)->length;
if (!TOY_IS_NULL(second)) {
if (TOY_IS_INDEX_BLANK(second)) {
Toy_freeLiteral(second);
second = TOY_TO_INTEGER_LITERAL(compoundLength - 1);
}
if (TOY_IS_IDENTIFIER(second)) {
Toy_Literal idn = second;
Toy_parseIdentifierToValue(interpreter, &second);
Toy_freeLiteral(idn);
}
}
if (TOY_IS_NULL(third) || TOY_IS_INDEX_BLANK(third)) {
Toy_freeLiteral(third);
third = TOY_TO_INTEGER_LITERAL(1);
}
if (TOY_IS_IDENTIFIER(first)) {
Toy_Literal idn = first;
Toy_parseIdentifierToValue(interpreter, &first);
Toy_freeLiteral(idn);
}
if (TOY_IS_IDENTIFIER(first) || TOY_IS_IDENTIFIER(second) || TOY_IS_IDENTIFIER(third)) {
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return -1;
}
//handle each error case
if (!TOY_IS_INTEGER(first) || TOY_AS_INTEGER(first) < 0 || TOY_AS_INTEGER(first) >= (int)Toy_lengthRefString(TOY_AS_STRING(compound))) {
interpreter->errorOutput("Bad first indexing in string assignment\n");
//something is weird - skip out
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return -1;
}
if ((!TOY_IS_NULL(second) && !TOY_IS_INTEGER(second)) || TOY_AS_INTEGER(second) < 0 || TOY_AS_INTEGER(second) >= (int)Toy_lengthRefString(TOY_AS_STRING(compound))) {
interpreter->errorOutput("Bad second indexing in string assignment\n");
//something is weird - skip out
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return -1;
}
if ((!TOY_IS_NULL(third) && !TOY_IS_INTEGER(third)) || TOY_AS_INTEGER(third) == 0) {
interpreter->errorOutput("Bad third indexing in string assignment\n");
//something is weird - skip out
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return -1;
}
//start building a new string from the old one
char* result = TOY_ALLOCATE(char, TOY_MAX_STRING_LENGTH);
//if third is abs(1), simply insert into the correct positions
int resultIndex = 0;
if (TOY_AS_INTEGER(third) == 1 || TOY_AS_INTEGER(third) == -1) {
for (int i = 0; i < TOY_AS_INTEGER(first); i++) {
result[ resultIndex++ ] = Toy_toCString(TOY_AS_STRING(compound))[ i ];
}
int assignLength = TOY_AS_STRING(assign)->length;
int min = TOY_AS_INTEGER(third) > 0 ? 0 : assignLength - 1;
for (int i = min; i >= 0 && i < assignLength; i += TOY_AS_INTEGER(third)) {
result[ resultIndex++ ] = Toy_toCString(TOY_AS_STRING(assign))[ i ];
}
for (int i = TOY_AS_INTEGER(second) + 1; i < compoundLength; i++) {
result[ resultIndex++ ] = Toy_toCString(TOY_AS_STRING(compound))[ i ];
}
result[ resultIndex ] = '\0';
}
//else override elements of the array instead
else {
//copy compound to result
snprintf(result, TOY_MAX_STRING_LENGTH, "%s", Toy_toCString(TOY_AS_STRING(compound)));
int assignLength = TOY_AS_STRING(assign)->length;
int min = TOY_AS_INTEGER(third) > 0 ? TOY_AS_INTEGER(first) : TOY_AS_INTEGER(second) - 1;
int assignIndex = 0;
for (int i = min; i >= TOY_AS_INTEGER(first) && i <= TOY_AS_INTEGER(second) && assignIndex < assignLength; i += TOY_AS_INTEGER(third)) {
result[ i ] = Toy_toCString(TOY_AS_STRING(assign))[ assignIndex++ ];
}
resultIndex = strlen(result);
}
//finally, swap out the compound for the result
Toy_freeLiteral(compound);
compound = TOY_TO_STRING_LITERAL(Toy_createRefStringLength(result, resultIndex));
TOY_FREE_ARRAY(char, result, TOY_MAX_STRING_LENGTH);
//leave the string on the stack
Toy_pushLiteralArray(&interpreter->stack, compound);
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return 1;
}
else if (TOY_IS_STRING(op) && Toy_equalsRefStringCString(TOY_AS_STRING(op), "+=")) {
Toy_Literal tmp = addition(interpreter, compound, assign);
Toy_freeLiteral(compound);
compound = tmp; //don't clear tmp
}
//leave the string on the stack
Toy_pushLiteralArray(&interpreter->stack, compound);
Toy_freeLiteral(op);
Toy_freeLiteral(assign);
Toy_freeLiteral(third);
Toy_freeLiteral(second);
Toy_freeLiteral(first);
Toy_freeLiteral(compound);
return 1;
}
return -1;
}
int Toy_private_set(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//if wrong number of arguments, fail
if (arguments->count != 3) {
interpreter->errorOutput("Incorrect number of arguments to set\n");
return -1;
}
Toy_Literal idn = arguments->literals[0];
Toy_Literal obj = arguments->literals[0];
Toy_Literal key = arguments->literals[1];
Toy_Literal val = arguments->literals[2];
if (!TOY_IS_IDENTIFIER(idn)) {
interpreter->errorOutput("Expected identifier in set\n");
return -1;
}
Toy_parseIdentifierToValue(interpreter, &obj);
if (TOY_IS_IDENTIFIER(obj)) {
return -1;
}
bool freeKey = false;
if (TOY_IS_IDENTIFIER(key)) {
Toy_parseIdentifierToValue(interpreter, &key);
freeKey = true;
}
bool freeVal = false;
if (TOY_IS_IDENTIFIER(val)) {
Toy_parseIdentifierToValue(interpreter, &val);
freeVal = true;
}
if (TOY_IS_IDENTIFIER(key) || TOY_IS_IDENTIFIER(val)) {
if (freeKey) {
Toy_freeLiteral(key);
}
if (freeVal) {
Toy_freeLiteral(val);
}
return -1;
}
switch(obj.type) {
case TOY_LITERAL_ARRAY: {
//check the subtype of the array, if there is one, against the given argument
Toy_Literal typeLiteral = Toy_getScopeType(interpreter->scope, idn);
if (TOY_AS_TYPE(typeLiteral).typeOf == TOY_LITERAL_ARRAY) {
Toy_Literal subtypeLiteral = ((Toy_Literal*)(TOY_AS_TYPE(typeLiteral).subtypes))[0];
if (TOY_AS_TYPE(subtypeLiteral).typeOf != TOY_LITERAL_ANY && TOY_AS_TYPE(subtypeLiteral).typeOf != val.type) {
interpreter->errorOutput("Bad argument type in set\n");
Toy_freeLiteral(typeLiteral);
return -1;
}
}
Toy_freeLiteral(typeLiteral);
if (!TOY_IS_INTEGER(key)) {
interpreter->errorOutput("Expected integer index in set\n");
return -1;
}
if (TOY_AS_INTEGER(key) >= TOY_AS_ARRAY(obj)->count || TOY_AS_INTEGER(key) < 0) {
interpreter->errorOutput("Index out of bounds in set\n");
return -1;
}
//don't use pushLiteralArray, since we're setting
Toy_freeLiteral(TOY_AS_ARRAY(obj)->literals[TOY_AS_INTEGER(key)]); //BUGFIX: clear any existing data first
TOY_AS_ARRAY(obj)->literals[TOY_AS_INTEGER(key)] = Toy_copyLiteral(val);
if (!Toy_setScopeVariable(interpreter->scope, idn, obj, true)) {
interpreter->errorOutput("Incorrect type assigned to array in set: \"");
Toy_printLiteralCustom(val, interpreter->errorOutput);
interpreter->errorOutput("\"\n");
return -1;
}
break;
}
case TOY_LITERAL_DICTIONARY: {
Toy_Literal typeLiteral = Toy_getScopeType(interpreter->scope, key);
if (TOY_AS_TYPE(typeLiteral).typeOf == TOY_LITERAL_DICTIONARY) {
Toy_Literal keySubtypeLiteral = ((Toy_Literal*)(TOY_AS_TYPE(typeLiteral).subtypes))[0];
Toy_Literal valSubtypeLiteral = ((Toy_Literal*)(TOY_AS_TYPE(typeLiteral).subtypes))[1];
if (TOY_AS_TYPE(keySubtypeLiteral).typeOf != TOY_LITERAL_ANY && TOY_AS_TYPE(keySubtypeLiteral).typeOf != key.type) {
interpreter->printOutput("bad argument type in set\n");
return -1;
}
if (TOY_AS_TYPE(valSubtypeLiteral).typeOf != TOY_LITERAL_ANY && TOY_AS_TYPE(valSubtypeLiteral).typeOf != val.type) {
interpreter->printOutput("bad argument type in set\n");
return -1;
}
}
Toy_setLiteralDictionary(TOY_AS_DICTIONARY(obj), key, val);
if (!Toy_setScopeVariable(interpreter->scope, idn, obj, true)) {
interpreter->errorOutput("Incorrect type assigned to dictionary in set: \"");
Toy_printLiteralCustom(val, interpreter->errorOutput);
interpreter->errorOutput("\"\n");
return -1;
}
break;
}
default:
interpreter->errorOutput("Incorrect compound type in set: ");
Toy_printLiteralCustom(obj, interpreter->errorOutput);
interpreter->errorOutput("\"\n");
return -1;
}
Toy_freeLiteral(obj);
if (freeKey) {
Toy_freeLiteral(key);
}
if (freeVal) {
Toy_freeLiteral(val);
}
return 0;
}
int Toy_private_get(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//if wrong number of arguments, fail
if (arguments->count != 2) {
interpreter->errorOutput("Incorrect number of arguments to get");
return -1;
}
Toy_Literal obj = arguments->literals[0];
Toy_Literal key = arguments->literals[1];
bool freeObj = false;
if (TOY_IS_IDENTIFIER(obj)) {
Toy_parseIdentifierToValue(interpreter, &obj);
freeObj = true;
}
bool freeKey = false;
if (TOY_IS_IDENTIFIER(key)) {
Toy_parseIdentifierToValue(interpreter, &key);
freeKey = true;
}
if (TOY_IS_IDENTIFIER(obj) || TOY_IS_IDENTIFIER(key)) {
if (freeObj) {
Toy_freeLiteral(obj);
}
if (freeKey) {
Toy_freeLiteral(key);
}
return -1;
}
switch(obj.type) {
case TOY_LITERAL_ARRAY: {
if (!TOY_IS_INTEGER(key)) {
interpreter->errorOutput("Expected integer index in get\n");
return -1;
}
if (TOY_AS_INTEGER(key) >= TOY_AS_ARRAY(obj)->count || TOY_AS_INTEGER(key) < 0) {
interpreter->errorOutput("Index out of bounds in get\n");
return -1;
}
Toy_pushLiteralArray(&interpreter->stack, TOY_AS_ARRAY(obj)->literals[TOY_AS_INTEGER(key)]);
if (freeObj) {
Toy_freeLiteral(obj);
}
if (freeKey) {
Toy_freeLiteral(key);
}
return 1;
}
case TOY_LITERAL_DICTIONARY: {
Toy_Literal dict = Toy_getLiteralDictionary(TOY_AS_DICTIONARY(obj), key);
Toy_pushLiteralArray(&interpreter->stack, dict);
Toy_freeLiteral(dict);
if (freeObj) {
Toy_freeLiteral(obj);
}
if (freeKey) {
Toy_freeLiteral(key);
}
return 1;
}
default:
interpreter->errorOutput("Incorrect compound type in get \"");
Toy_printLiteralCustom(obj, interpreter->errorOutput);
interpreter->errorOutput("\"\n");
return -1;
}
}
int Toy_private_push(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//if wrong number of arguments, fail
if (arguments->count != 2) {
interpreter->errorOutput("Incorrect number of arguments to push\n");
return -1;
}
Toy_Literal idn = arguments->literals[0];
Toy_Literal obj = arguments->literals[0];
Toy_Literal val = arguments->literals[1];
if (!TOY_IS_IDENTIFIER(idn)) {
interpreter->errorOutput("Expected identifier in push\n");
return -1;
}
Toy_parseIdentifierToValue(interpreter, &obj);
if (TOY_IS_IDENTIFIER(obj)) {
return -1;
}
bool freeVal = false;
if (TOY_IS_IDENTIFIER(val)) {
Toy_parseIdentifierToValue(interpreter, &val);
freeVal = true;
}
if (TOY_IS_IDENTIFIER(val)) {
return -1;
}
switch(obj.type) {
case TOY_LITERAL_ARRAY: {
//check the subtype of the array, if there is one, against the given argument
Toy_Literal typeLiteral = Toy_getScopeType(interpreter->scope, idn);
if (TOY_AS_TYPE(typeLiteral).typeOf == TOY_LITERAL_ARRAY) {
Toy_Literal subtypeLiteral = ((Toy_Literal*)(TOY_AS_TYPE(typeLiteral).subtypes))[0];
if (TOY_AS_TYPE(subtypeLiteral).typeOf != TOY_LITERAL_ANY && TOY_AS_TYPE(subtypeLiteral).typeOf != val.type) {
interpreter->errorOutput("Bad argument type in push");
Toy_freeLiteral(typeLiteral);
return -1;
}
}
Toy_freeLiteral(typeLiteral);
Toy_pushLiteralArray(TOY_AS_ARRAY(obj), val);
if (!Toy_setScopeVariable(interpreter->scope, idn, obj, true)) { //TODO: could definitely be more efficient than overwriting the whole original object
interpreter->errorOutput("Incorrect type assigned to array in push: \"");
Toy_printLiteralCustom(val, interpreter->errorOutput);
interpreter->errorOutput("\"\n");
return -1;
}
Toy_freeLiteral(obj);
if (freeVal) {
Toy_freeLiteral(val);
}
return 0;
}
default:
interpreter->errorOutput("Incorrect compound type in push: ");
Toy_printLiteralCustom(obj, interpreter->errorOutput);
interpreter->errorOutput("\n");
return -1;
}
}
int Toy_private_pop(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//if wrong number of arguments, fail
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to pop\n");
return -1;
}
Toy_Literal idn = arguments->literals[0];
Toy_Literal obj = arguments->literals[0];
if (!TOY_IS_IDENTIFIER(idn)) {
interpreter->errorOutput("Expected identifier in pop\n");
return -1;
}
Toy_parseIdentifierToValue(interpreter, &obj);
if (TOY_IS_IDENTIFIER(obj)) {
return -1;
}
switch(obj.type) {
case TOY_LITERAL_ARRAY: {
Toy_Literal lit = Toy_popLiteralArray(TOY_AS_ARRAY(obj));
Toy_pushLiteralArray(&interpreter->stack, lit);
Toy_freeLiteral(lit);
if (!Toy_setScopeVariable(interpreter->scope, idn, obj, true)) { //TODO: could definitely be more efficient than overwriting the whole original object
interpreter->errorOutput("Incorrect type assigned to array in pop: ");
Toy_printLiteralCustom(obj, interpreter->errorOutput);
interpreter->errorOutput("\n");
return -1;
}
Toy_freeLiteral(obj);
return 1;
}
default:
interpreter->errorOutput("Incorrect compound type in pop: ");
Toy_printLiteralCustom(obj, interpreter->errorOutput);
interpreter->errorOutput("\n");
return -1;
}
}
int Toy_private_length(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//if wrong number of arguments, fail
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to length\n");
return -1;
}
Toy_Literal obj = arguments->literals[0];
bool freeObj = false;
if (TOY_IS_IDENTIFIER(obj)) {
Toy_parseIdentifierToValue(interpreter, &obj);
freeObj = true;
}
if (TOY_IS_IDENTIFIER(obj)) {
return -1;
}
switch(obj.type) {
case TOY_LITERAL_ARRAY: {
Toy_Literal lit = TOY_TO_INTEGER_LITERAL( TOY_AS_ARRAY(obj)->count );
Toy_pushLiteralArray(&interpreter->stack, lit);
Toy_freeLiteral(lit);
break;
}
case TOY_LITERAL_DICTIONARY: {
Toy_Literal lit = TOY_TO_INTEGER_LITERAL( TOY_AS_DICTIONARY(obj)->count );
Toy_pushLiteralArray(&interpreter->stack, lit);
Toy_freeLiteral(lit);
break;
}
case TOY_LITERAL_STRING: {
Toy_Literal lit = TOY_TO_INTEGER_LITERAL( TOY_AS_STRING(obj)->length );
Toy_pushLiteralArray(&interpreter->stack, lit);
Toy_freeLiteral(lit);
break;
}
default:
interpreter->errorOutput("Incorrect compound type in length: ");
Toy_printLiteralCustom(obj, interpreter->errorOutput);
interpreter->errorOutput("\n");
return -1;
}
if (freeObj) {
Toy_freeLiteral(obj);
}
return 1;
}
int Toy_private_clear(Toy_Interpreter* interpreter, Toy_LiteralArray* arguments) {
//if wrong number of arguments, fail
if (arguments->count != 1) {
interpreter->errorOutput("Incorrect number of arguments to clear\n");
return -1;
}
Toy_Literal idn = arguments->literals[0];
Toy_Literal obj = arguments->literals[0];
if (!TOY_IS_IDENTIFIER(idn)) {
interpreter->errorOutput("expected identifier in clear\n");
return -1;
}
Toy_parseIdentifierToValue(interpreter, &obj);
if (TOY_IS_IDENTIFIER(obj)) {
return -1;
}
//NOTE: just pass in new compounds
switch(obj.type) {
case TOY_LITERAL_ARRAY: {
Toy_LiteralArray* array = TOY_ALLOCATE(Toy_LiteralArray, 1);
Toy_initLiteralArray(array);
Toy_Literal obj = TOY_TO_ARRAY_LITERAL(array);
if (!Toy_setScopeVariable(interpreter->scope, idn, obj, true)) {
interpreter->errorOutput("Incorrect type assigned to array in clear: ");
Toy_printLiteralCustom(obj, interpreter->errorOutput);
interpreter->errorOutput("\n");
return -1;
}
Toy_freeLiteral(obj);
break;
}
case TOY_LITERAL_DICTIONARY: {
Toy_LiteralDictionary* dictionary = TOY_ALLOCATE(Toy_LiteralDictionary, 1);
Toy_initLiteralDictionary(dictionary);
Toy_Literal obj = TOY_TO_DICTIONARY_LITERAL(dictionary);
if (!Toy_setScopeVariable(interpreter->scope, idn, obj, true)) {
interpreter->errorOutput("Incorrect type assigned to dictionary in clear: ");
Toy_printLiteralCustom(obj, interpreter->errorOutput);
interpreter->errorOutput("\n");
return -1;
}
Toy_freeLiteral(obj);
break;
}
default:
interpreter->errorOutput("Incorrect compound type in clear: ");
Toy_printLiteralCustom(obj, interpreter->errorOutput);
interpreter->errorOutput("\n");
return -1;
}
Toy_freeLiteral(obj);
return 1;
}