mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 14:54:07 +10:00
WIP: Implementing arrays into the script, read more
I had intended to solve the Advent of Code puzzles in Toy, but they don't work without arrays. I wasn't able to enable arrays in time, so I need to focus on doing things correctly. The most immediate tasks are marked with 'URGENT', and a lot of tests need writing.
This commit is contained in:
@@ -341,6 +341,8 @@ static void debugStackPrint(Toy_Stack* stack) {
|
|||||||
|
|
||||||
printf("%s\t", Toy_private_getValueTypeAsCString(v.type));
|
printf("%s\t", Toy_private_getValueTypeAsCString(v.type));
|
||||||
|
|
||||||
|
v = Toy_unwrapValue(v);
|
||||||
|
|
||||||
switch(v.type) {
|
switch(v.type) {
|
||||||
case TOY_VALUE_NULL:
|
case TOY_VALUE_NULL:
|
||||||
printf("null");
|
printf("null");
|
||||||
@@ -382,6 +384,7 @@ static void debugStackPrint(Toy_Stack* stack) {
|
|||||||
case TOY_VALUE_OPAQUE:
|
case TOY_VALUE_OPAQUE:
|
||||||
case TOY_VALUE_TYPE:
|
case TOY_VALUE_TYPE:
|
||||||
case TOY_VALUE_ANY:
|
case TOY_VALUE_ANY:
|
||||||
|
case TOY_VALUE_REFERENCE:
|
||||||
case TOY_VALUE_UNKNOWN:
|
case TOY_VALUE_UNKNOWN:
|
||||||
printf("???");
|
printf("???");
|
||||||
break;
|
break;
|
||||||
@@ -406,6 +409,9 @@ static void debugScopePrint(Toy_Scope* scope, int depth) {
|
|||||||
|
|
||||||
printf("%s\t%s\t", Toy_private_getValueTypeAsCString(v.type), TOY_VALUE_AS_STRING(k)->as.name.data);
|
printf("%s\t%s\t", Toy_private_getValueTypeAsCString(v.type), TOY_VALUE_AS_STRING(k)->as.name.data);
|
||||||
|
|
||||||
|
k = Toy_unwrapValue(k);
|
||||||
|
v = Toy_unwrapValue(v);
|
||||||
|
|
||||||
switch(v.type) {
|
switch(v.type) {
|
||||||
case TOY_VALUE_NULL:
|
case TOY_VALUE_NULL:
|
||||||
printf("null");
|
printf("null");
|
||||||
@@ -447,6 +453,7 @@ static void debugScopePrint(Toy_Scope* scope, int depth) {
|
|||||||
case TOY_VALUE_OPAQUE:
|
case TOY_VALUE_OPAQUE:
|
||||||
case TOY_VALUE_TYPE:
|
case TOY_VALUE_TYPE:
|
||||||
case TOY_VALUE_ANY:
|
case TOY_VALUE_ANY:
|
||||||
|
case TOY_VALUE_REFERENCE:
|
||||||
case TOY_VALUE_UNKNOWN:
|
case TOY_VALUE_UNKNOWN:
|
||||||
printf("???");
|
printf("???");
|
||||||
break;
|
break;
|
||||||
|
|||||||
27
scripts/advent_1a.toy
Normal file
27
scripts/advent_1a.toy
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
//advent of code thingy
|
||||||
|
var arr = [
|
||||||
|
3, 4,
|
||||||
|
4, 3,
|
||||||
|
2, 5,
|
||||||
|
1, 3,
|
||||||
|
3, 9,
|
||||||
|
3 , 3
|
||||||
|
];
|
||||||
|
|
||||||
|
var total = 0;
|
||||||
|
var counter = 0;
|
||||||
|
|
||||||
|
while (counter < arr.length) {
|
||||||
|
var difference = arr[counter] - arr[counter+1];
|
||||||
|
|
||||||
|
if (difference < 0) {
|
||||||
|
difference = -difference;
|
||||||
|
}
|
||||||
|
|
||||||
|
total += difference;
|
||||||
|
|
||||||
|
counter += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
print difference;
|
||||||
|
|
||||||
@@ -40,3 +40,5 @@ TOY_API Toy_Array* Toy_resizeArray(Toy_Array* array, unsigned int capacity);
|
|||||||
#ifndef TOY_ARRAY_PUSHBACK
|
#ifndef TOY_ARRAY_PUSHBACK
|
||||||
#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
|
||||||
|
|||||||
@@ -84,13 +84,23 @@ void Toy_private_emitAstGroup(Toy_Bucket** bucketHandle, Toy_Ast** astHandle) {
|
|||||||
(*astHandle) = tmp;
|
(*astHandle) = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Toy_private_emitAstCompound(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_AstFlag flag, Toy_Ast* right) {
|
void Toy_private_emitAstCompound(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_AstFlag flag) {
|
||||||
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast));
|
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast));
|
||||||
|
|
||||||
tmp->type = TOY_AST_COMPOUND;
|
tmp->type = TOY_AST_COMPOUND;
|
||||||
tmp->compound.flag = flag;
|
tmp->compound.flag = flag;
|
||||||
tmp->compound.left = *astHandle; //left-recursive
|
tmp->compound.child = *astHandle;
|
||||||
tmp->compound.right = right;
|
|
||||||
|
(*astHandle) = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Toy_private_emitAstAggregate(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_AstFlag flag, Toy_Ast* right) {
|
||||||
|
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast));
|
||||||
|
|
||||||
|
tmp->type = TOY_AST_AGGREGATE;
|
||||||
|
tmp->aggregate.flag = flag;
|
||||||
|
tmp->aggregate.left = *astHandle; //left-recursive
|
||||||
|
tmp->aggregate.right = right;
|
||||||
|
|
||||||
(*astHandle) = tmp;
|
(*astHandle) = tmp;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ typedef enum Toy_AstType {
|
|||||||
TOY_AST_COMPARE,
|
TOY_AST_COMPARE,
|
||||||
TOY_AST_GROUP,
|
TOY_AST_GROUP,
|
||||||
TOY_AST_COMPOUND,
|
TOY_AST_COMPOUND,
|
||||||
|
TOY_AST_AGGREGATE,
|
||||||
|
|
||||||
TOY_AST_ASSERT,
|
TOY_AST_ASSERT,
|
||||||
TOY_AST_IF_THEN_ELSE,
|
TOY_AST_IF_THEN_ELSE,
|
||||||
@@ -58,8 +59,10 @@ typedef enum Toy_AstFlag {
|
|||||||
TOY_AST_FLAG_COMPARE_GREATER = 24,
|
TOY_AST_FLAG_COMPARE_GREATER = 24,
|
||||||
TOY_AST_FLAG_COMPARE_GREATER_EQUAL = 25,
|
TOY_AST_FLAG_COMPARE_GREATER_EQUAL = 25,
|
||||||
|
|
||||||
TOY_AST_FLAG_COMPOUND_COLLECTION = 30,
|
TOY_AST_FLAG_COMPOUND_ARRAY = 30,
|
||||||
TOY_AST_FLAG_COMPOUND_INDEX = 31,
|
// TOY_AST_FLAG_COMPOUND_TABLE = 31,
|
||||||
|
TOY_AST_FLAG_COLLECTION = 32,
|
||||||
|
TOY_AST_FLAG_INDEX = 33,
|
||||||
|
|
||||||
TOY_AST_FLAG_AND = 40,
|
TOY_AST_FLAG_AND = 40,
|
||||||
TOY_AST_FLAG_OR = 41,
|
TOY_AST_FLAG_OR = 41,
|
||||||
@@ -115,11 +118,17 @@ typedef struct Toy_AstGroup {
|
|||||||
} Toy_AstGroup;
|
} Toy_AstGroup;
|
||||||
|
|
||||||
typedef struct Toy_AstCompound {
|
typedef struct Toy_AstCompound {
|
||||||
|
Toy_AstType type;
|
||||||
|
Toy_AstFlag flag;
|
||||||
|
Toy_Ast* child;
|
||||||
|
} Toy_AstCompound;
|
||||||
|
|
||||||
|
typedef struct Toy_AstAggregate {
|
||||||
Toy_AstType type;
|
Toy_AstType type;
|
||||||
Toy_AstFlag flag;
|
Toy_AstFlag flag;
|
||||||
Toy_Ast* left;
|
Toy_Ast* left;
|
||||||
Toy_Ast* right;
|
Toy_Ast* right;
|
||||||
} Toy_AstCompound;
|
} Toy_AstAggregate;
|
||||||
|
|
||||||
typedef struct Toy_AstAssert {
|
typedef struct Toy_AstAssert {
|
||||||
Toy_AstType type;
|
Toy_AstType type;
|
||||||
@@ -191,7 +200,8 @@ union Toy_Ast { //32 | 64 BITNESS
|
|||||||
Toy_AstBinary binary; //16 | 24
|
Toy_AstBinary binary; //16 | 24
|
||||||
Toy_AstCompare compare; //16 | 24
|
Toy_AstCompare compare; //16 | 24
|
||||||
Toy_AstGroup group; //8 | 16
|
Toy_AstGroup group; //8 | 16
|
||||||
Toy_AstCompound compound; //16 | 24
|
Toy_AstCompound compound; //12 | 16
|
||||||
|
Toy_AstAggregate aggregate; //16 | 24
|
||||||
Toy_AstAssert assert; //16 | 24
|
Toy_AstAssert assert; //16 | 24
|
||||||
Toy_AstIfThenElse ifThenElse; //16 | 32
|
Toy_AstIfThenElse ifThenElse; //16 | 32
|
||||||
Toy_AstWhileThen whileThen; //16 | 24
|
Toy_AstWhileThen whileThen; //16 | 24
|
||||||
@@ -214,7 +224,8 @@ void Toy_private_emitAstUnary(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, To
|
|||||||
void Toy_private_emitAstBinary(Toy_Bucket** bucketHandle, Toy_Ast** astHandle,Toy_AstFlag flag, Toy_Ast* right);
|
void Toy_private_emitAstBinary(Toy_Bucket** bucketHandle, Toy_Ast** astHandle,Toy_AstFlag flag, Toy_Ast* right);
|
||||||
void Toy_private_emitAstCompare(Toy_Bucket** bucketHandle, Toy_Ast** astHandle,Toy_AstFlag flag, Toy_Ast* right);
|
void Toy_private_emitAstCompare(Toy_Bucket** bucketHandle, Toy_Ast** astHandle,Toy_AstFlag flag, Toy_Ast* right);
|
||||||
void Toy_private_emitAstGroup(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);
|
void Toy_private_emitAstGroup(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);
|
||||||
void Toy_private_emitAstCompound(Toy_Bucket** bucketHandle, Toy_Ast** astHandle,Toy_AstFlag flag, Toy_Ast* right);
|
void Toy_private_emitAstCompound(Toy_Bucket** bucketHandle, Toy_Ast** astHandle,Toy_AstFlag flag);
|
||||||
|
void Toy_private_emitAstAggregate(Toy_Bucket** bucketHandle, Toy_Ast** astHandle,Toy_AstFlag flag, Toy_Ast* right);
|
||||||
|
|
||||||
void Toy_private_emitAstAssert(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_Ast* child, Toy_Ast* msg);
|
void Toy_private_emitAstAssert(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_Ast* child, Toy_Ast* msg);
|
||||||
void Toy_private_emitAstIfThenElse(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_Ast* condBranch, Toy_Ast* thenBranch, Toy_Ast* elseBranch);
|
void Toy_private_emitAstIfThenElse(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_Ast* condBranch, Toy_Ast* thenBranch, Toy_Ast* elseBranch);
|
||||||
|
|||||||
@@ -117,6 +117,7 @@ static Toy_AstFlag unary(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast*
|
|||||||
static Toy_AstFlag binary(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle);
|
static Toy_AstFlag binary(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle);
|
||||||
static Toy_AstFlag group(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle);
|
static Toy_AstFlag group(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle);
|
||||||
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);
|
||||||
|
static Toy_AstFlag aggregate(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle);
|
||||||
|
|
||||||
//precedence definitions
|
//precedence definitions
|
||||||
static ParsingTuple parsingRulesetTable[] = {
|
static ParsingTuple parsingRulesetTable[] = {
|
||||||
@@ -195,7 +196,7 @@ static ParsingTuple parsingRulesetTable[] = {
|
|||||||
//structural operators
|
//structural operators
|
||||||
{PREC_NONE,group,NULL},// TOY_TOKEN_OPERATOR_PAREN_LEFT,
|
{PREC_NONE,group,NULL},// TOY_TOKEN_OPERATOR_PAREN_LEFT,
|
||||||
{PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_PAREN_RIGHT,
|
{PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_PAREN_RIGHT,
|
||||||
{PREC_GROUP,NULL,compound},// TOY_TOKEN_OPERATOR_BRACKET_LEFT,
|
{PREC_GROUP,compound,aggregate},// TOY_TOKEN_OPERATOR_BRACKET_LEFT,
|
||||||
{PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_BRACKET_RIGHT,
|
{PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_BRACKET_RIGHT,
|
||||||
{PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_BRACE_LEFT,
|
{PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_BRACE_LEFT,
|
||||||
{PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_BRACE_RIGHT,
|
{PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_BRACE_RIGHT,
|
||||||
@@ -208,7 +209,7 @@ static ParsingTuple parsingRulesetTable[] = {
|
|||||||
{PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_COLON,
|
{PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_COLON,
|
||||||
|
|
||||||
{PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_SEMICOLON, // ;
|
{PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_SEMICOLON, // ;
|
||||||
{PREC_GROUP,NULL,compound},// TOY_TOKEN_OPERATOR_COMMA, // ,
|
{PREC_GROUP,NULL,aggregate},// TOY_TOKEN_OPERATOR_COMMA, // ,
|
||||||
|
|
||||||
{PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_DOT, // .
|
{PREC_NONE,NULL,NULL},// TOY_TOKEN_OPERATOR_DOT, // .
|
||||||
{PREC_CALL,NULL,binary},// TOY_TOKEN_OPERATOR_CONCAT, // ..
|
{PREC_CALL,NULL,binary},// TOY_TOKEN_OPERATOR_CONCAT, // ..
|
||||||
@@ -562,17 +563,16 @@ 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) {
|
||||||
//infix must advance
|
//read in an array or dictionary aggregate
|
||||||
advance(parser);
|
|
||||||
|
|
||||||
if (parser->previous.type == TOY_TOKEN_OPERATOR_COMMA) {
|
if (parser->previous.type == TOY_TOKEN_OPERATOR_BRACKET_LEFT) {
|
||||||
parsePrecedence(bucketHandle, parser, rootHandle, PREC_GROUP); //NOT +1, as compounds are right-recursive
|
|
||||||
return TOY_AST_FLAG_COMPOUND_COLLECTION;
|
|
||||||
}
|
|
||||||
else 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 index expression");
|
consume(parser, TOY_TOKEN_OPERATOR_BRACKET_RIGHT, "Expected ']' at the end of compound expression");
|
||||||
return TOY_AST_FLAG_COMPOUND_INDEX;
|
Toy_private_emitAstCompound(bucketHandle, rootHandle, TOY_AST_FLAG_COMPOUND_ARRAY);
|
||||||
|
|
||||||
|
return TOY_AST_FLAG_NONE;
|
||||||
|
|
||||||
|
//TODO: read in a dictionary
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
printError(parser, parser->previous, "Unexpected token passed to compound precedence rule");
|
printError(parser, parser->previous, "Unexpected token passed to compound precedence rule");
|
||||||
@@ -581,6 +581,31 @@ static Toy_AstFlag compound(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_A
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Toy_AstFlag aggregate(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {
|
||||||
|
//infix must advance
|
||||||
|
advance(parser);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
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");
|
||||||
|
return TOY_AST_FLAG_INDEX;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printError(parser, parser->previous, "Unexpected token passed to aggregate precedence rule");
|
||||||
|
Toy_private_emitAstError(bucketHandle, rootHandle);
|
||||||
|
return TOY_AST_FLAG_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: allow trailing commas
|
||||||
|
// static Toy_AstFlag noop(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {
|
||||||
|
// return return TOY_AST_FLAG_NONE;
|
||||||
|
// }
|
||||||
|
|
||||||
static ParsingTuple* getParsingRule(Toy_TokenType type) {
|
static ParsingTuple* getParsingRule(Toy_TokenType type) {
|
||||||
return &parsingRulesetTable[type];
|
return &parsingRulesetTable[type];
|
||||||
}
|
}
|
||||||
@@ -638,7 +663,7 @@ static void parsePrecedence(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_A
|
|||||||
Toy_private_emitAstCompare(bucketHandle, rootHandle, flag, ptr);
|
Toy_private_emitAstCompare(bucketHandle, rootHandle, flag, ptr);
|
||||||
}
|
}
|
||||||
else if (flag >= 30 && flag <= 39) {
|
else if (flag >= 30 && flag <= 39) {
|
||||||
Toy_private_emitAstCompound(bucketHandle, rootHandle, flag, ptr);
|
Toy_private_emitAstAggregate(bucketHandle, rootHandle, flag, ptr);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Toy_private_emitAstBinary(bucketHandle, rootHandle, flag, ptr);
|
Toy_private_emitAstBinary(bucketHandle, rootHandle, flag, ptr);
|
||||||
@@ -668,9 +693,9 @@ static void makeAssertStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_As
|
|||||||
Toy_private_emitAstPass(bucketHandle, rootHandle);
|
Toy_private_emitAstPass(bucketHandle, rootHandle);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
//NOTE: if it's a compound, then it's got a second arg
|
//NOTE: if it's an aggregate node, then it's got a second arg
|
||||||
if (ast->type == TOY_AST_COMPOUND) {
|
if (ast->type == TOY_AST_AGGREGATE) {
|
||||||
Toy_private_emitAstAssert(bucketHandle, rootHandle, ast->compound.left, ast->compound.right);
|
Toy_private_emitAstAssert(bucketHandle, rootHandle, ast->aggregate.left, ast->aggregate.right);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Toy_private_emitAstAssert(bucketHandle, rootHandle, ast, NULL);
|
Toy_private_emitAstAssert(bucketHandle, rootHandle, ast, NULL);
|
||||||
|
|||||||
@@ -208,7 +208,7 @@ static unsigned int writeInstructionBinary(Toy_Routine** rt, Toy_AstBinary ast)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//4-byte alignment
|
//4-byte alignment
|
||||||
EMIT_BYTE(rt, code,TOY_OPCODE_PASS); //checked in compound assignments
|
EMIT_BYTE(rt, code,TOY_OPCODE_PASS); //checked in combined assignments
|
||||||
EMIT_BYTE(rt, code,0);
|
EMIT_BYTE(rt, code,0);
|
||||||
EMIT_BYTE(rt, code,0);
|
EMIT_BYTE(rt, code,0);
|
||||||
|
|
||||||
@@ -263,17 +263,41 @@ static unsigned int writeInstructionGroup(Toy_Routine** rt, Toy_AstGroup ast) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int writeInstructionCompound(Toy_Routine** rt, Toy_AstCompound ast) {
|
static unsigned int writeInstructionCompound(Toy_Routine** rt, Toy_AstCompound ast) {
|
||||||
|
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
|
||||||
|
EMIT_BYTE(rt, code, TOY_OPCODE_READ);
|
||||||
|
EMIT_BYTE(rt, code, TOY_VALUE_ARRAY);
|
||||||
|
|
||||||
|
//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);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int writeInstructionAggregate(Toy_Routine** rt, Toy_AstAggregate ast) {
|
||||||
unsigned int result = 0;
|
unsigned int result = 0;
|
||||||
|
|
||||||
//left, then right
|
//left, then right
|
||||||
result += writeRoutineCode(rt, ast.left);
|
result += writeRoutineCode(rt, ast.left);
|
||||||
result += writeRoutineCode(rt, ast.right);
|
result += writeRoutineCode(rt, ast.right);
|
||||||
|
|
||||||
if (ast.flag == TOY_AST_FLAG_COMPOUND_COLLECTION) {
|
if (ast.flag == TOY_AST_FLAG_COLLECTION) {
|
||||||
//collections are handled above
|
//collections are handled above
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
else if (ast.flag == TOY_AST_FLAG_COMPOUND_INDEX) {
|
else if (ast.flag == TOY_AST_FLAG_INDEX) {
|
||||||
//value[index, length]
|
//value[index, length]
|
||||||
EMIT_BYTE(rt, code, TOY_OPCODE_INDEX);
|
EMIT_BYTE(rt, code, TOY_OPCODE_INDEX);
|
||||||
EMIT_BYTE(rt, code, result);
|
EMIT_BYTE(rt, code, result);
|
||||||
@@ -285,7 +309,7 @@ static unsigned int writeInstructionCompound(Toy_Routine** rt, Toy_AstCompound a
|
|||||||
return 1; //leaves only 1 value on the stack
|
return 1; //leaves only 1 value on the stack
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid AST compound flag found\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid AST aggregate flag found\n" TOY_CC_RESET);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -429,10 +453,12 @@ 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:
|
||||||
case TOY_AST_COMPOUND:
|
case TOY_AST_AGGREGATE:
|
||||||
case TOY_AST_ASSERT:
|
case TOY_AST_ASSERT:
|
||||||
case TOY_AST_PRINT:
|
case TOY_AST_PRINT:
|
||||||
case TOY_AST_VAR_DECLARE:
|
case TOY_AST_VAR_DECLARE:
|
||||||
@@ -594,7 +620,7 @@ static unsigned int writeRoutineCode(Toy_Routine** rt, Toy_Ast* ast) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//NOTE: 'result' is used to in 'writeInstructionCompound()'
|
//NOTE: 'result' is used to in 'writeInstructionAggregate()'
|
||||||
unsigned int result = 0;
|
unsigned int result = 0;
|
||||||
|
|
||||||
//determine how to write each instruction based on the Ast
|
//determine how to write each instruction based on the Ast
|
||||||
@@ -642,6 +668,10 @@ static unsigned int writeRoutineCode(Toy_Routine** rt, Toy_Ast* ast) {
|
|||||||
result += writeInstructionCompound(rt, ast->compound);
|
result += writeInstructionCompound(rt, ast->compound);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TOY_AST_AGGREGATE:
|
||||||
|
result += writeInstructionAggregate(rt, ast->aggregate);
|
||||||
|
break;
|
||||||
|
|
||||||
case TOY_AST_ASSERT:
|
case TOY_AST_ASSERT:
|
||||||
result += writeInstructionAssert(rt, ast->assert);
|
result += writeInstructionAssert(rt, ast->assert);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
#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) {
|
||||||
@@ -126,6 +128,8 @@ void Toy_declareScope(Toy_Scope* scope, Toy_String* key, Toy_Value value) {
|
|||||||
Toy_insertTable(&scope->table, TOY_VALUE_FROM_STRING(Toy_copyString(key)), value);
|
Toy_insertTable(&scope->table, TOY_VALUE_FROM_STRING(Toy_copyString(key)), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//TODO: check for clearign old values
|
||||||
void Toy_assignScope(Toy_Scope* scope, Toy_String* key, Toy_Value value) {
|
void Toy_assignScope(Toy_Scope* scope, Toy_String* key, Toy_Value value) {
|
||||||
if (key->type != TOY_STRING_NAME) {
|
if (key->type != TOY_STRING_NAME) {
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Toy_Scope only allows name strings as keys\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Toy_Scope only allows name strings as keys\n" TOY_CC_RESET);
|
||||||
@@ -161,7 +165,7 @@ void Toy_assignScope(Toy_Scope* scope, Toy_String* key, Toy_Value value) {
|
|||||||
entryPtr->value = value;
|
entryPtr->value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Toy_Value Toy_accessScope(Toy_Scope* scope, Toy_String* key) {
|
Toy_Value* Toy_accessScopeAsPointer(Toy_Scope* scope, Toy_String* key) {
|
||||||
if (key->type != TOY_STRING_NAME) {
|
if (key->type != TOY_STRING_NAME) {
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Toy_Scope only allows name strings as keys\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Toy_Scope only allows name strings as keys\n" TOY_CC_RESET);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
@@ -173,10 +177,10 @@ Toy_Value Toy_accessScope(Toy_Scope* scope, Toy_String* key) {
|
|||||||
char buffer[key->length + 256];
|
char buffer[key->length + 256];
|
||||||
sprintf(buffer, "Undefined variable: %s\n", key->as.name.data);
|
sprintf(buffer, "Undefined variable: %s\n", key->as.name.data);
|
||||||
Toy_error(buffer);
|
Toy_error(buffer);
|
||||||
return TOY_VALUE_FROM_NULL();
|
NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return entryPtr->value;
|
return &(entryPtr->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Toy_isDeclaredScope(Toy_Scope* scope, Toy_String* key) {
|
bool Toy_isDeclaredScope(Toy_Scope* scope, Toy_String* key) {
|
||||||
|
|||||||
@@ -23,6 +23,6 @@ TOY_API Toy_Scope* Toy_deepCopyScope(Toy_Bucket** bucketHandle, Toy_Scope* scope
|
|||||||
//manage the contents
|
//manage the contents
|
||||||
TOY_API void Toy_declareScope(Toy_Scope* scope, Toy_String* key, Toy_Value value);
|
TOY_API void Toy_declareScope(Toy_Scope* scope, Toy_String* key, Toy_Value value);
|
||||||
TOY_API void Toy_assignScope(Toy_Scope* scope, Toy_String* key, Toy_Value value);
|
TOY_API void Toy_assignScope(Toy_Scope* scope, Toy_String* key, Toy_Value value);
|
||||||
TOY_API Toy_Value Toy_accessScope(Toy_Scope* scope, Toy_String* key);
|
TOY_API Toy_Value* Toy_accessScopeAsPointer(Toy_Scope* scope, Toy_String* key);
|
||||||
|
|
||||||
TOY_API bool Toy_isDeclaredScope(Toy_Scope* scope, Toy_String* key);
|
TOY_API bool Toy_isDeclaredScope(Toy_Scope* scope, Toy_String* key);
|
||||||
|
|||||||
@@ -18,30 +18,42 @@ static unsigned int hashUInt(unsigned int x) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//exposed functions
|
//exposed functions
|
||||||
|
Toy_Value Toy_unwrapValue(Toy_Value value) {
|
||||||
|
//turns out C doesn't have actual references
|
||||||
|
if (value.type == TOY_VALUE_REFERENCE) {
|
||||||
|
return Toy_unwrapValue(*(value.as.reference));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unsigned int Toy_hashValue(Toy_Value value) {
|
unsigned int Toy_hashValue(Toy_Value value) {
|
||||||
|
value = Toy_unwrapValue(value);
|
||||||
|
|
||||||
switch(value.type) {
|
switch(value.type) {
|
||||||
case TOY_VALUE_NULL:
|
case TOY_VALUE_NULL:
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case TOY_VALUE_BOOLEAN:
|
case TOY_VALUE_BOOLEAN:
|
||||||
return TOY_VALUE_AS_BOOLEAN(value) ? 1 : 0;
|
return value.as.boolean ? 1 : 0;
|
||||||
|
|
||||||
case TOY_VALUE_INTEGER:
|
case TOY_VALUE_INTEGER:
|
||||||
return hashUInt(TOY_VALUE_AS_INTEGER(value));
|
return hashUInt((unsigned int)value.as.integer);
|
||||||
|
|
||||||
case TOY_VALUE_FLOAT:
|
case TOY_VALUE_FLOAT:
|
||||||
return hashUInt( *((int*)(&TOY_VALUE_AS_FLOAT(value))) );
|
return hashUInt( *((unsigned int*)(&value.as.number)) );
|
||||||
|
|
||||||
case TOY_VALUE_STRING:
|
case TOY_VALUE_STRING:
|
||||||
return Toy_hashString(TOY_VALUE_AS_STRING(value));
|
return Toy_hashString(value.as.string);
|
||||||
|
|
||||||
case TOY_VALUE_ARRAY: {
|
case TOY_VALUE_ARRAY: {
|
||||||
//since array internals can change, recalc the hash each time it's needed
|
//since array internals can change, recalc the hash each time it's needed
|
||||||
Toy_Array* array = TOY_VALUE_AS_ARRAY(value);
|
Toy_Array* ptr = value.as.array;
|
||||||
unsigned int hash = 0;
|
unsigned int hash = 0;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < array->count; i++) {
|
for (unsigned int i = 0; i < ptr->count; i++) {
|
||||||
hash ^= Toy_hashValue(array->data[i]);
|
hash ^= Toy_hashValue(ptr->data[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return hash;
|
return hash;
|
||||||
@@ -52,6 +64,7 @@ unsigned int Toy_hashValue(Toy_Value value) {
|
|||||||
case TOY_VALUE_OPAQUE:
|
case TOY_VALUE_OPAQUE:
|
||||||
case TOY_VALUE_TYPE:
|
case TOY_VALUE_TYPE:
|
||||||
case TOY_VALUE_ANY:
|
case TOY_VALUE_ANY:
|
||||||
|
case TOY_VALUE_REFERENCE:
|
||||||
case TOY_VALUE_UNKNOWN:
|
case TOY_VALUE_UNKNOWN:
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Can't hash an unknown value type, exiting\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Can't hash an unknown value type, exiting\n" TOY_CC_RESET);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
@@ -61,6 +74,8 @@ unsigned int Toy_hashValue(Toy_Value value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Toy_Value Toy_copyValue(Toy_Value value) {
|
Toy_Value Toy_copyValue(Toy_Value value) {
|
||||||
|
value = Toy_unwrapValue(value);
|
||||||
|
|
||||||
switch(value.type) {
|
switch(value.type) {
|
||||||
case TOY_VALUE_NULL:
|
case TOY_VALUE_NULL:
|
||||||
case TOY_VALUE_BOOLEAN:
|
case TOY_VALUE_BOOLEAN:
|
||||||
@@ -69,20 +84,20 @@ Toy_Value Toy_copyValue(Toy_Value value) {
|
|||||||
return value;
|
return value;
|
||||||
|
|
||||||
case TOY_VALUE_STRING: {
|
case TOY_VALUE_STRING: {
|
||||||
Toy_String* string = TOY_VALUE_AS_STRING(value);
|
return TOY_VALUE_FROM_STRING(Toy_copyString(value.as.string));
|
||||||
return TOY_VALUE_FROM_STRING(Toy_copyString(string));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_VALUE_ARRAY: {
|
case TOY_VALUE_ARRAY: {
|
||||||
Toy_Array* array = TOY_VALUE_AS_ARRAY(value);
|
//arrays probably won't get copied much
|
||||||
Toy_Array* result = Toy_resizeArray(NULL, array->capacity);
|
Toy_Array* ptr = value.as.array;
|
||||||
|
Toy_Array* result = Toy_resizeArray(NULL, ptr->capacity);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < array->count; i++) {
|
for (unsigned int i = 0; i < ptr->count; i++) {
|
||||||
result->data[i] = Toy_copyValue(array->data[i]);
|
result->data[i] = Toy_copyValue(ptr->data[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
result->capacity = array->capacity;
|
result->capacity = ptr->capacity;
|
||||||
result->count = array->count;
|
result->count = ptr->count;
|
||||||
|
|
||||||
return TOY_VALUE_FROM_ARRAY(result);
|
return TOY_VALUE_FROM_ARRAY(result);
|
||||||
}
|
}
|
||||||
@@ -92,6 +107,7 @@ Toy_Value Toy_copyValue(Toy_Value value) {
|
|||||||
case TOY_VALUE_OPAQUE:
|
case TOY_VALUE_OPAQUE:
|
||||||
case TOY_VALUE_TYPE:
|
case TOY_VALUE_TYPE:
|
||||||
case TOY_VALUE_ANY:
|
case TOY_VALUE_ANY:
|
||||||
|
case TOY_VALUE_REFERENCE:
|
||||||
case TOY_VALUE_UNKNOWN:
|
case TOY_VALUE_UNKNOWN:
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Can't copy an unknown value type, exiting\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Can't copy an unknown value type, exiting\n" TOY_CC_RESET);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
@@ -102,6 +118,8 @@ Toy_Value Toy_copyValue(Toy_Value value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Toy_freeValue(Toy_Value value) {
|
void Toy_freeValue(Toy_Value value) {
|
||||||
|
//NOTE: do not unwrap this value, as references shouldn't be freed
|
||||||
|
|
||||||
switch(value.type) {
|
switch(value.type) {
|
||||||
case TOY_VALUE_NULL:
|
case TOY_VALUE_NULL:
|
||||||
case TOY_VALUE_BOOLEAN:
|
case TOY_VALUE_BOOLEAN:
|
||||||
@@ -110,19 +128,18 @@ void Toy_freeValue(Toy_Value value) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case TOY_VALUE_STRING: {
|
case TOY_VALUE_STRING: {
|
||||||
Toy_String* string = TOY_VALUE_AS_STRING(value);
|
Toy_freeString(value.as.string);
|
||||||
Toy_freeString(string);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_VALUE_ARRAY: {
|
case TOY_VALUE_ARRAY: {
|
||||||
Toy_Array* array = TOY_VALUE_AS_ARRAY(value);
|
Toy_Array* ptr = value.as.array;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < array->count; i++) {
|
for (unsigned int i = 0; i < ptr->count; i++) {
|
||||||
Toy_freeValue(array->data[i]);
|
Toy_freeValue(ptr->data[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
TOY_ARRAY_FREE(array);
|
TOY_ARRAY_FREE(ptr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,6 +148,7 @@ void Toy_freeValue(Toy_Value value) {
|
|||||||
case TOY_VALUE_OPAQUE:
|
case TOY_VALUE_OPAQUE:
|
||||||
case TOY_VALUE_TYPE:
|
case TOY_VALUE_TYPE:
|
||||||
case TOY_VALUE_ANY:
|
case TOY_VALUE_ANY:
|
||||||
|
case TOY_VALUE_REFERENCE:
|
||||||
case TOY_VALUE_UNKNOWN:
|
case TOY_VALUE_UNKNOWN:
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Can't free an unknown value type, exiting\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Can't free an unknown value type, exiting\n" TOY_CC_RESET);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
@@ -138,15 +156,17 @@ void Toy_freeValue(Toy_Value value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Toy_checkValueIsTruthy(Toy_Value value) {
|
bool Toy_checkValueIsTruthy(Toy_Value value) {
|
||||||
|
value = Toy_unwrapValue(value);
|
||||||
|
|
||||||
//null is an error
|
//null is an error
|
||||||
if (TOY_VALUE_IS_NULL(value)) {
|
if (value.type == TOY_VALUE_NULL) {
|
||||||
Toy_error("'null' is neither true nor false");
|
Toy_error("'null' is neither true nor false");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//only 'false' is falsy
|
//only 'false' is falsy
|
||||||
if (TOY_VALUE_IS_BOOLEAN(value)) {
|
if (value.type == TOY_VALUE_BOOLEAN) {
|
||||||
return TOY_VALUE_AS_BOOLEAN(value);
|
return value.as.boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
//anything else is truthy
|
//anything else is truthy
|
||||||
@@ -154,57 +174,65 @@ bool Toy_checkValueIsTruthy(Toy_Value value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Toy_checkValuesAreEqual(Toy_Value left, Toy_Value right) {
|
bool Toy_checkValuesAreEqual(Toy_Value left, Toy_Value right) {
|
||||||
|
left = Toy_unwrapValue(left);
|
||||||
|
right = Toy_unwrapValue(right);
|
||||||
|
|
||||||
switch(left.type) {
|
switch(left.type) {
|
||||||
case TOY_VALUE_NULL:
|
case TOY_VALUE_NULL:
|
||||||
return TOY_VALUE_IS_NULL(right);
|
return right.type == TOY_VALUE_NULL;
|
||||||
|
|
||||||
case TOY_VALUE_BOOLEAN:
|
case TOY_VALUE_BOOLEAN:
|
||||||
return TOY_VALUE_IS_BOOLEAN(right) && TOY_VALUE_AS_BOOLEAN(left) == TOY_VALUE_AS_BOOLEAN(right);
|
return right.type == TOY_VALUE_NULL && left.as.boolean == right.as.boolean;
|
||||||
|
|
||||||
case TOY_VALUE_INTEGER:
|
case TOY_VALUE_INTEGER:
|
||||||
if (TOY_VALUE_IS_INTEGER(right)) {
|
if (right.type == TOY_VALUE_INTEGER) {
|
||||||
return TOY_VALUE_AS_INTEGER(left) == TOY_VALUE_AS_INTEGER(right);
|
return left.as.integer == right.as.integer;
|
||||||
}
|
}
|
||||||
else if (TOY_VALUE_IS_FLOAT(right)) {
|
else if (right.type == TOY_VALUE_FLOAT) {
|
||||||
return TOY_VALUE_AS_INTEGER(left) == TOY_VALUE_AS_FLOAT(right);
|
return left.as.integer == right.as.number;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_VALUE_FLOAT:
|
case TOY_VALUE_FLOAT:
|
||||||
if (TOY_VALUE_IS_INTEGER(right)) {
|
if (right.type == TOY_VALUE_INTEGER) {
|
||||||
return TOY_VALUE_AS_FLOAT(left) == TOY_VALUE_AS_INTEGER(right);
|
return left.as.number == right.as.integer;
|
||||||
}
|
}
|
||||||
else if (TOY_VALUE_IS_FLOAT(right)) {
|
else if (right.type == TOY_VALUE_FLOAT) {
|
||||||
return TOY_VALUE_AS_FLOAT(left) == TOY_VALUE_AS_FLOAT(right);
|
return left.as.number == right.as.number;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_VALUE_STRING:
|
case TOY_VALUE_STRING:
|
||||||
if (TOY_VALUE_IS_STRING(right)) {
|
if (right.type == TOY_VALUE_STRING) {
|
||||||
return Toy_compareStrings(TOY_VALUE_AS_STRING(left), TOY_VALUE_AS_STRING(right)) == 0;
|
return Toy_compareStrings(left.as.string, right.as.string) == 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_VALUE_ARRAY: {
|
case TOY_VALUE_ARRAY: {
|
||||||
Toy_Array* leftArray = TOY_VALUE_AS_ARRAY(left);
|
if (right.type == TOY_VALUE_ARRAY) {
|
||||||
Toy_Array* rightArray = TOY_VALUE_AS_ARRAY(right);
|
Toy_Array* leftArray = left.as.array;
|
||||||
|
Toy_Array* rightArray = right.as.array;
|
||||||
|
|
||||||
//different lengths is an easy way to check
|
//different lengths is an easy way to check
|
||||||
if (leftArray->count != rightArray->count) {
|
if (leftArray->count != rightArray->count) {
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < leftArray->count; i++) {
|
|
||||||
//any mismatch is an easy difference
|
|
||||||
if (Toy_checkValuesAreEqual(leftArray->data[i], rightArray->data[i])) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < leftArray->count; i++) {
|
||||||
|
//any mismatch is an easy difference
|
||||||
|
if (Toy_checkValuesAreEqual(leftArray->data[i], rightArray->data[i])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
//finally
|
//finally
|
||||||
@@ -216,6 +244,7 @@ bool Toy_checkValuesAreEqual(Toy_Value left, Toy_Value right) {
|
|||||||
case TOY_VALUE_OPAQUE:
|
case TOY_VALUE_OPAQUE:
|
||||||
case TOY_VALUE_TYPE:
|
case TOY_VALUE_TYPE:
|
||||||
case TOY_VALUE_ANY:
|
case TOY_VALUE_ANY:
|
||||||
|
case TOY_VALUE_REFERENCE:
|
||||||
case TOY_VALUE_UNKNOWN:
|
case TOY_VALUE_UNKNOWN:
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Unknown types in value equality, exiting\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Unknown types in value equality, exiting\n" TOY_CC_RESET);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
@@ -225,21 +254,23 @@ bool Toy_checkValuesAreEqual(Toy_Value left, Toy_Value right) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Toy_checkValuesAreComparable(Toy_Value left, Toy_Value right) {
|
bool Toy_checkValuesAreComparable(Toy_Value left, Toy_Value right) {
|
||||||
//NOTE: "equal" and "comparable" are different - equal means they're identical, comparable is only possible for certain types
|
left = Toy_unwrapValue(left);
|
||||||
|
right = Toy_unwrapValue(right);
|
||||||
|
|
||||||
|
//NOTE: "equal" and "comparable" are different - equal means they're identical, comparable is only possible for certain types
|
||||||
switch(left.type) {
|
switch(left.type) {
|
||||||
case TOY_VALUE_NULL:
|
case TOY_VALUE_NULL:
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
case TOY_VALUE_BOOLEAN:
|
case TOY_VALUE_BOOLEAN:
|
||||||
return TOY_VALUE_IS_BOOLEAN(right);
|
return right.type == TOY_VALUE_BOOLEAN;
|
||||||
|
|
||||||
case TOY_VALUE_INTEGER:
|
case TOY_VALUE_INTEGER:
|
||||||
case TOY_VALUE_FLOAT:
|
case TOY_VALUE_FLOAT:
|
||||||
return TOY_VALUE_IS_INTEGER(right) || TOY_VALUE_IS_FLOAT(right);
|
return right.type == TOY_VALUE_INTEGER || right.type == TOY_VALUE_FLOAT;
|
||||||
|
|
||||||
case TOY_VALUE_STRING:
|
case TOY_VALUE_STRING:
|
||||||
return TOY_VALUE_IS_STRING(right);
|
return right.type == TOY_VALUE_STRING;
|
||||||
|
|
||||||
case TOY_VALUE_ARRAY:
|
case TOY_VALUE_ARRAY:
|
||||||
//nothing is comparable with an array
|
//nothing is comparable with an array
|
||||||
@@ -250,6 +281,7 @@ bool Toy_checkValuesAreComparable(Toy_Value left, Toy_Value right) {
|
|||||||
case TOY_VALUE_OPAQUE:
|
case TOY_VALUE_OPAQUE:
|
||||||
case TOY_VALUE_TYPE:
|
case TOY_VALUE_TYPE:
|
||||||
case TOY_VALUE_ANY:
|
case TOY_VALUE_ANY:
|
||||||
|
case TOY_VALUE_REFERENCE:
|
||||||
case TOY_VALUE_UNKNOWN:
|
case TOY_VALUE_UNKNOWN:
|
||||||
fprintf(stderr, TOY_CC_ERROR "Unknown types in value comparison check, exiting\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "Unknown types in value comparison check, exiting\n" TOY_CC_RESET);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
@@ -259,6 +291,9 @@ bool Toy_checkValuesAreComparable(Toy_Value left, Toy_Value right) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int Toy_compareValues(Toy_Value left, Toy_Value right) {
|
int Toy_compareValues(Toy_Value left, Toy_Value right) {
|
||||||
|
left = Toy_unwrapValue(left);
|
||||||
|
right = Toy_unwrapValue(right);
|
||||||
|
|
||||||
//comparison means there's a difference in value, with some kind of quantity - so null, bool, etc. aren't comparable
|
//comparison means there's a difference in value, with some kind of quantity - so null, bool, etc. aren't comparable
|
||||||
switch(left.type) {
|
switch(left.type) {
|
||||||
case TOY_VALUE_NULL:
|
case TOY_VALUE_NULL:
|
||||||
@@ -266,30 +301,30 @@ int Toy_compareValues(Toy_Value left, Toy_Value right) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case TOY_VALUE_INTEGER:
|
case TOY_VALUE_INTEGER:
|
||||||
if (TOY_VALUE_IS_INTEGER(right)) {
|
if (right.type == TOY_VALUE_INTEGER) {
|
||||||
return TOY_VALUE_AS_INTEGER(left) - TOY_VALUE_AS_INTEGER(right);
|
return left.as.integer - right.as.integer;
|
||||||
}
|
}
|
||||||
else if (TOY_VALUE_IS_FLOAT(right)) {
|
else if (right.type == TOY_VALUE_FLOAT) {
|
||||||
return TOY_VALUE_AS_INTEGER(left) - TOY_VALUE_AS_FLOAT(right);
|
return left.as.integer - right.as.number;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_VALUE_FLOAT:
|
case TOY_VALUE_FLOAT:
|
||||||
if (TOY_VALUE_IS_INTEGER(right)) {
|
if (right.type == TOY_VALUE_INTEGER) {
|
||||||
return TOY_VALUE_AS_FLOAT(left) - TOY_VALUE_AS_INTEGER(right);
|
return left.as.number - right.as.integer;
|
||||||
}
|
}
|
||||||
else if (TOY_VALUE_IS_FLOAT(right)) {
|
else if (right.type == TOY_VALUE_FLOAT) {
|
||||||
return TOY_VALUE_AS_FLOAT(left) - TOY_VALUE_AS_FLOAT(right);
|
return left.as.number - right.as.number;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_VALUE_STRING:
|
case TOY_VALUE_STRING:
|
||||||
if (TOY_VALUE_IS_STRING(right)) {
|
if (right.type == TOY_VALUE_STRING) {
|
||||||
return Toy_compareStrings(TOY_VALUE_AS_STRING(left), TOY_VALUE_AS_STRING(right));
|
return Toy_compareStrings(left.as.string, right.as.string);
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_VALUE_ARRAY:
|
case TOY_VALUE_ARRAY:
|
||||||
@@ -300,15 +335,20 @@ int Toy_compareValues(Toy_Value left, Toy_Value right) {
|
|||||||
case TOY_VALUE_OPAQUE:
|
case TOY_VALUE_OPAQUE:
|
||||||
case TOY_VALUE_TYPE:
|
case TOY_VALUE_TYPE:
|
||||||
case TOY_VALUE_ANY:
|
case TOY_VALUE_ANY:
|
||||||
|
case TOY_VALUE_REFERENCE:
|
||||||
case TOY_VALUE_UNKNOWN:
|
case TOY_VALUE_UNKNOWN:
|
||||||
fprintf(stderr, TOY_CC_ERROR "Unknown types in value comparison, exiting\n" TOY_CC_RESET);
|
break;
|
||||||
exit(-1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
fprintf(stderr, TOY_CC_ERROR "Unknown types in value comparison, exiting\n" TOY_CC_RESET);
|
||||||
|
exit(-1);
|
||||||
|
|
||||||
|
return ~0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Toy_String* Toy_stringifyValue(Toy_Bucket** bucketHandle, Toy_Value value) {
|
Toy_String* Toy_stringifyValue(Toy_Bucket** bucketHandle, Toy_Value value) {
|
||||||
|
value = Toy_unwrapValue(value);
|
||||||
|
|
||||||
//TODO: could have "constant" strings that can be referenced, instead of null, true, false, etc.
|
//TODO: could have "constant" strings that can be referenced, instead of null, true, false, etc.
|
||||||
|
|
||||||
switch(value.type) {
|
switch(value.type) {
|
||||||
@@ -316,18 +356,18 @@ Toy_String* Toy_stringifyValue(Toy_Bucket** bucketHandle, Toy_Value value) {
|
|||||||
return Toy_createString(bucketHandle, "null");
|
return Toy_createString(bucketHandle, "null");
|
||||||
|
|
||||||
case TOY_VALUE_BOOLEAN:
|
case TOY_VALUE_BOOLEAN:
|
||||||
return Toy_createString(bucketHandle, TOY_VALUE_AS_BOOLEAN(value) ? "true" : "false");
|
return Toy_createString(bucketHandle, value.as.boolean ? "true" : "false");
|
||||||
|
|
||||||
case TOY_VALUE_INTEGER: {
|
case TOY_VALUE_INTEGER: {
|
||||||
char buffer[16];
|
char buffer[16];
|
||||||
sprintf(buffer, "%d", TOY_VALUE_AS_INTEGER(value));
|
sprintf(buffer, "%d", value.as.integer);
|
||||||
return Toy_createString(bucketHandle, buffer);
|
return Toy_createString(bucketHandle, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_VALUE_FLOAT: {
|
case TOY_VALUE_FLOAT: {
|
||||||
//using printf
|
//using printf
|
||||||
char buffer[16];
|
char buffer[16];
|
||||||
sprintf(buffer, "%f", TOY_VALUE_AS_FLOAT(value));
|
sprintf(buffer, "%f", value.as.number);
|
||||||
|
|
||||||
//BUGFIX: printf format specificer '%f' will set the precision to 6 decimal places, which means there's trailing zeroes
|
//BUGFIX: printf format specificer '%f' will set the precision to 6 decimal places, which means there's trailing zeroes
|
||||||
unsigned int length = strlen(buffer);
|
unsigned int length = strlen(buffer);
|
||||||
@@ -343,28 +383,33 @@ Toy_String* Toy_stringifyValue(Toy_Bucket** bucketHandle, Toy_Value value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case TOY_VALUE_STRING:
|
case TOY_VALUE_STRING:
|
||||||
return Toy_copyString(TOY_VALUE_AS_STRING(value));
|
return Toy_copyString(value.as.string);
|
||||||
|
|
||||||
case TOY_VALUE_ARRAY: {
|
case TOY_VALUE_ARRAY: {
|
||||||
//TODO: concat + free is definitely a performance nightmare
|
//TODO: concat + free is definitely a performance nightmare, could make an append function?
|
||||||
Toy_Array* array = TOY_VALUE_AS_ARRAY(value);
|
Toy_Array* ptr = value.as.array;
|
||||||
Toy_String* string = Toy_createStringLength(bucketHandle, "[", 1);
|
Toy_String* string = Toy_createStringLength(bucketHandle, "[", 1);
|
||||||
Toy_String* comma = Toy_createStringLength(bucketHandle, ",", 1); //reusable
|
Toy_String* comma = Toy_createStringLength(bucketHandle, ",", 1); //reusable
|
||||||
|
|
||||||
for (unsigned int i = 0; i < array->count; i++) {
|
for (unsigned int i = 0; i < ptr->count; i++) {
|
||||||
//append each element
|
//append each element
|
||||||
Toy_String* tmp = Toy_concatStrings(bucketHandle, string, Toy_stringifyValue(bucketHandle, array->data[i])); //increment ref
|
Toy_String* tmp = Toy_concatStrings(bucketHandle, string, Toy_stringifyValue(bucketHandle, ptr->data[i])); //increment ref
|
||||||
Toy_freeString(string); //decrement ref
|
Toy_freeString(string); //decrement ref
|
||||||
string = tmp;
|
string = tmp;
|
||||||
|
|
||||||
//if we need a comma
|
//if we need a comma
|
||||||
if (i + 1 < array->count) {
|
if (i + 1 < ptr->count) {
|
||||||
Toy_String* tmp = Toy_concatStrings(bucketHandle, string, comma); //increment ref
|
Toy_String* tmp = Toy_concatStrings(bucketHandle, string, comma); //increment ref
|
||||||
Toy_freeString(string); //decrement ref
|
Toy_freeString(string); //decrement ref
|
||||||
string = tmp;
|
string = tmp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//closing bracket
|
||||||
|
Toy_String* tmp = Toy_concatStrings(bucketHandle, string, Toy_createStringLength(bucketHandle, "]", 1));
|
||||||
|
Toy_freeString(string);
|
||||||
|
string = tmp;
|
||||||
|
|
||||||
//clean up
|
//clean up
|
||||||
Toy_freeString(comma); //TODO: reusable global, or string type "permanent"
|
Toy_freeString(comma); //TODO: reusable global, or string type "permanent"
|
||||||
|
|
||||||
@@ -376,6 +421,7 @@ Toy_String* Toy_stringifyValue(Toy_Bucket** bucketHandle, Toy_Value value) {
|
|||||||
case TOY_VALUE_OPAQUE:
|
case TOY_VALUE_OPAQUE:
|
||||||
case TOY_VALUE_TYPE:
|
case TOY_VALUE_TYPE:
|
||||||
case TOY_VALUE_ANY:
|
case TOY_VALUE_ANY:
|
||||||
|
case TOY_VALUE_REFERENCE:
|
||||||
case TOY_VALUE_UNKNOWN:
|
case TOY_VALUE_UNKNOWN:
|
||||||
fprintf(stderr, TOY_CC_ERROR "Unknown types in value stringify, exiting\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "Unknown types in value stringify, exiting\n" TOY_CC_RESET);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
@@ -397,6 +443,7 @@ const char* Toy_private_getValueTypeAsCString(Toy_ValueType type) {
|
|||||||
case TOY_VALUE_OPAQUE: return "opaque";
|
case TOY_VALUE_OPAQUE: return "opaque";
|
||||||
case TOY_VALUE_TYPE: return "type";
|
case TOY_VALUE_TYPE: return "type";
|
||||||
case TOY_VALUE_ANY: return "any";
|
case TOY_VALUE_ANY: return "any";
|
||||||
|
case TOY_VALUE_REFERENCE: return "reference";
|
||||||
case TOY_VALUE_UNKNOWN: return "unknown";
|
case TOY_VALUE_UNKNOWN: return "unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,39 +20,45 @@ typedef enum Toy_ValueType {
|
|||||||
TOY_VALUE_OPAQUE,
|
TOY_VALUE_OPAQUE,
|
||||||
TOY_VALUE_TYPE,
|
TOY_VALUE_TYPE,
|
||||||
TOY_VALUE_ANY,
|
TOY_VALUE_ANY,
|
||||||
|
|
||||||
|
TOY_VALUE_REFERENCE, //not a value itself, but pointing to one
|
||||||
TOY_VALUE_UNKNOWN, //The correct type is unknown, but will be determined later
|
TOY_VALUE_UNKNOWN, //The correct type is unknown, but will be determined later
|
||||||
} Toy_ValueType;
|
} Toy_ValueType;
|
||||||
|
|
||||||
//8 bytes in size
|
//8 bytes in size
|
||||||
typedef struct Toy_Value { //32 | 64 BITNESS
|
typedef struct Toy_Value { //32 | 64 BITNESS
|
||||||
union {
|
union {
|
||||||
bool boolean; //1 | 1
|
struct Toy_Value* reference; //4 | 8
|
||||||
int integer; //4 | 4
|
bool boolean; //1 | 1
|
||||||
float number; //4 | 4
|
int integer; //4 | 4
|
||||||
struct Toy_String* string; //4 | 8
|
float number; //4 | 4
|
||||||
struct Toy_Array* array; //4 | 8
|
struct Toy_String* string; //4 | 8
|
||||||
|
struct Toy_Array* array; //4 | 8
|
||||||
//TODO: more types go here
|
//TODO: more types go here
|
||||||
//TODO: consider 'stack' as a possible addition
|
//TODO: consider 'stack' as a possible addition
|
||||||
} as; //4 | 8
|
|
||||||
|
|
||||||
Toy_ValueType type; //4 | 4
|
} as; //4 | 8
|
||||||
} Toy_Value; //8 | 16
|
|
||||||
|
|
||||||
#define TOY_VALUE_IS_NULL(value) ((value).type == TOY_VALUE_NULL)
|
Toy_ValueType type; //4 | 4
|
||||||
#define TOY_VALUE_IS_BOOLEAN(value) ((value).type == TOY_VALUE_BOOLEAN)
|
} Toy_Value; //8 | 16
|
||||||
#define TOY_VALUE_IS_INTEGER(value) ((value).type == TOY_VALUE_INTEGER)
|
|
||||||
#define TOY_VALUE_IS_FLOAT(value) ((value).type == TOY_VALUE_FLOAT)
|
|
||||||
#define TOY_VALUE_IS_STRING(value) ((value).type == TOY_VALUE_STRING)
|
|
||||||
#define TOY_VALUE_IS_ARRAY(value) ((value).type == TOY_VALUE_ARRAY)
|
|
||||||
#define TOY_VALUE_IS_TABLE(value) ((value).type == TOY_VALUE_TABLE)
|
|
||||||
#define TOY_VALUE_IS_FUNCTION(value) ((value).type == TOY_VALUE_FUNCTION)
|
|
||||||
#define TOY_VALUE_IS_OPAQUE(value) ((value).type == TOY_VALUE_OPAQUE)
|
|
||||||
|
|
||||||
#define TOY_VALUE_AS_BOOLEAN(value) ((value).as.boolean)
|
#define TOY_VALUE_IS_NULL(value) (Toy_unwrapValue(value).type == TOY_VALUE_NULL)
|
||||||
#define TOY_VALUE_AS_INTEGER(value) ((value).as.integer)
|
#define TOY_VALUE_IS_BOOLEAN(value) (Toy_unwrapValue(value).type == TOY_VALUE_BOOLEAN)
|
||||||
#define TOY_VALUE_AS_FLOAT(value) ((value).as.number)
|
#define TOY_VALUE_IS_INTEGER(value) (Toy_unwrapValue(value).type == TOY_VALUE_INTEGER)
|
||||||
#define TOY_VALUE_AS_STRING(value) ((value).as.string)
|
#define TOY_VALUE_IS_FLOAT(value) (Toy_unwrapValue(value).type == TOY_VALUE_FLOAT)
|
||||||
#define TOY_VALUE_AS_ARRAY(value) ((value).as.array)
|
#define TOY_VALUE_IS_STRING(value) (Toy_unwrapValue(value).type == TOY_VALUE_STRING)
|
||||||
|
#define TOY_VALUE_IS_ARRAY(value) (Toy_unwrapValue(value).type == TOY_VALUE_ARRAY)
|
||||||
|
#define TOY_VALUE_IS_TABLE(value) (Toy_unwrapValue(value).type == TOY_VALUE_TABLE)
|
||||||
|
#define TOY_VALUE_IS_FUNCTION(value) (Toy_unwrapValue(value).type == TOY_VALUE_FUNCTION)
|
||||||
|
#define TOY_VALUE_IS_OPAQUE(value) (Toy_unwrapValue(value).type == TOY_VALUE_OPAQUE)
|
||||||
|
#define TOY_VALUE_IS_TYPE(value) (Toy_unwrapValue(value).type == TOY_VALUE_TYPE)
|
||||||
|
#define TOY_VALUE_IS_REFERENCE(value) ((value).type == TOY_VALUE_REFERENCE)
|
||||||
|
|
||||||
|
#define TOY_VALUE_AS_BOOLEAN(value) (Toy_unwrapValue(value).as.boolean)
|
||||||
|
#define TOY_VALUE_AS_INTEGER(value) (Toy_unwrapValue(value).as.integer)
|
||||||
|
#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)
|
||||||
//TODO: more
|
//TODO: more
|
||||||
|
|
||||||
#define TOY_VALUE_FROM_NULL() ((Toy_Value){{ .integer = 0 }, TOY_VALUE_NULL})
|
#define TOY_VALUE_FROM_NULL() ((Toy_Value){{ .integer = 0 }, TOY_VALUE_NULL})
|
||||||
@@ -63,7 +69,10 @@ typedef struct Toy_Value { //32 | 64 BITNESS
|
|||||||
#define TOY_VALUE_FROM_ARRAY(value) ((Toy_Value){{ .array = value }, TOY_VALUE_ARRAY})
|
#define TOY_VALUE_FROM_ARRAY(value) ((Toy_Value){{ .array = value }, TOY_VALUE_ARRAY})
|
||||||
//TODO: more
|
//TODO: more
|
||||||
|
|
||||||
|
#define TOY_REFERENCE_FROM_POINTER(ptr) ((Toy_Value){{ .reference = ptr }, TOY_VALUE_REFERENCE})
|
||||||
|
|
||||||
//utilities
|
//utilities
|
||||||
|
TOY_API Toy_Value Toy_unwrapValue(Toy_Value value);
|
||||||
TOY_API unsigned int Toy_hashValue(Toy_Value value);
|
TOY_API unsigned int Toy_hashValue(Toy_Value value);
|
||||||
|
|
||||||
TOY_API Toy_Value Toy_copyValue(Toy_Value value);
|
TOY_API Toy_Value Toy_copyValue(Toy_Value value);
|
||||||
|
|||||||
252
source/toy_vm.c
252
source/toy_vm.c
@@ -5,6 +5,7 @@
|
|||||||
#include "toy_opcodes.h"
|
#include "toy_opcodes.h"
|
||||||
#include "toy_value.h"
|
#include "toy_value.h"
|
||||||
#include "toy_string.h"
|
#include "toy_string.h"
|
||||||
|
#include "toy_array.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -90,8 +91,34 @@ static void processRead(Toy_VM* vm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case TOY_VALUE_ARRAY: {
|
case TOY_VALUE_ARRAY: {
|
||||||
//
|
fixAlignment(vm);
|
||||||
// break;
|
|
||||||
|
//the number of values to read from the stack
|
||||||
|
unsigned int count = (unsigned int)READ_INT(vm);
|
||||||
|
unsigned int capacity = count > TOY_ARRAY_INITIAL_CAPACITY ? count : TOY_ARRAY_INITIAL_CAPACITY;
|
||||||
|
|
||||||
|
//neat trick to find the next power of two, inclusive (restriction of the array 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 array and read in the values
|
||||||
|
Toy_Array* array = Toy_resizeArray(NULL, capacity);
|
||||||
|
array->capacity = capacity;
|
||||||
|
array->count = count;
|
||||||
|
|
||||||
|
for (int i = count - 1; i >= 0; i--) { //read in backwards from the stack
|
||||||
|
array->data[i] = Toy_popStack(&vm->stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
//finished
|
||||||
|
value = TOY_VALUE_FROM_ARRAY(array);
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_VALUE_TABLE: {
|
case TOY_VALUE_TABLE: {
|
||||||
@@ -174,6 +201,8 @@ static void processAssign(Toy_VM* vm) {
|
|||||||
//assign it
|
//assign it
|
||||||
Toy_assignScope(vm->scope, TOY_VALUE_AS_STRING(name), value);
|
Toy_assignScope(vm->scope, TOY_VALUE_AS_STRING(name), value);
|
||||||
|
|
||||||
|
//URGENT: complex assignments
|
||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
Toy_freeValue(name);
|
Toy_freeValue(name);
|
||||||
}
|
}
|
||||||
@@ -187,9 +216,20 @@ static void processAccess(Toy_VM* vm) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//find and push the value
|
//find the value
|
||||||
Toy_Value value = Toy_accessScope(vm->scope, TOY_VALUE_AS_STRING(name));
|
Toy_Value* valuePtr = Toy_accessScopeAsPointer(vm->scope, TOY_VALUE_AS_STRING(name));
|
||||||
Toy_pushStack(&vm->stack, Toy_copyValue(value));
|
|
||||||
|
//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);
|
||||||
|
|
||||||
|
Toy_pushStack(&vm->stack, ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
Toy_pushStack(&vm->stack, Toy_copyValue(*valuePtr));
|
||||||
|
}
|
||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
Toy_freeValue(name);
|
Toy_freeValue(name);
|
||||||
@@ -198,7 +238,6 @@ static void processAccess(Toy_VM* vm) {
|
|||||||
static void processDuplicate(Toy_VM* vm) {
|
static void processDuplicate(Toy_VM* vm) {
|
||||||
Toy_Value value = Toy_copyValue(Toy_peekStack(&vm->stack));
|
Toy_Value value = Toy_copyValue(Toy_peekStack(&vm->stack));
|
||||||
Toy_pushStack(&vm->stack, value);
|
Toy_pushStack(&vm->stack, value);
|
||||||
Toy_freeValue(value);
|
|
||||||
|
|
||||||
//check for compound assignments
|
//check for compound assignments
|
||||||
Toy_OpcodeType squeezed = READ_BYTE(vm);
|
Toy_OpcodeType squeezed = READ_BYTE(vm);
|
||||||
@@ -216,8 +255,15 @@ static void processArithmetic(Toy_VM* vm, Toy_OpcodeType opcode) {
|
|||||||
char buffer[256];
|
char buffer[256];
|
||||||
snprintf(buffer, 256, "Invalid types '%s' and '%s' passed in arithmetic", Toy_private_getValueTypeAsCString(left.type), Toy_private_getValueTypeAsCString(right.type));
|
snprintf(buffer, 256, "Invalid types '%s' and '%s' passed in arithmetic", Toy_private_getValueTypeAsCString(left.type), Toy_private_getValueTypeAsCString(right.type));
|
||||||
Toy_error(buffer);
|
Toy_error(buffer);
|
||||||
Toy_freeValue(left);
|
|
||||||
Toy_freeValue(right);
|
if (TOY_VALUE_IS_REFERENCE(left) != true) {
|
||||||
|
Toy_freeValue(left);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TOY_VALUE_IS_REFERENCE(right) != true) {
|
||||||
|
Toy_freeValue(right);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,17 +343,30 @@ static void processComparison(Toy_VM* vm, Toy_OpcodeType opcode) {
|
|||||||
Toy_pushStack(&vm->stack, TOY_VALUE_FROM_BOOLEAN(!equal) );
|
Toy_pushStack(&vm->stack, TOY_VALUE_FROM_BOOLEAN(!equal) );
|
||||||
}
|
}
|
||||||
|
|
||||||
Toy_freeValue(left);
|
if (TOY_VALUE_IS_REFERENCE(left) != true) {
|
||||||
Toy_freeValue(right);
|
Toy_freeValue(left);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TOY_VALUE_IS_REFERENCE(right) != true) {
|
||||||
|
Toy_freeValue(right);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Toy_checkValuesAreComparable(left, right) == false) {
|
if (Toy_checkValuesAreComparable(left, right) != true) {
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
snprintf(buffer, 256, "Can't compare value types '%s' and '%s'", Toy_private_getValueTypeAsCString(left.type), Toy_private_getValueTypeAsCString(right.type));
|
snprintf(buffer, 256, "Can't compare value types '%s' and '%s'", Toy_private_getValueTypeAsCString(left.type), Toy_private_getValueTypeAsCString(right.type));
|
||||||
Toy_error(buffer);
|
Toy_error(buffer);
|
||||||
Toy_freeValue(left);
|
|
||||||
Toy_freeValue(right);
|
if (TOY_VALUE_IS_REFERENCE(left) != true) {
|
||||||
|
Toy_freeValue(left);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TOY_VALUE_IS_REFERENCE(right) != true) {
|
||||||
|
Toy_freeValue(right);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,8 +392,13 @@ static void processComparison(Toy_VM* vm, Toy_OpcodeType opcode) {
|
|||||||
Toy_pushStack(&vm->stack, TOY_VALUE_FROM_BOOLEAN(false));
|
Toy_pushStack(&vm->stack, TOY_VALUE_FROM_BOOLEAN(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
Toy_freeValue(left);
|
if (TOY_VALUE_IS_REFERENCE(left) != true) {
|
||||||
Toy_freeValue(right);
|
Toy_freeValue(left);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TOY_VALUE_IS_REFERENCE(right) != true) {
|
||||||
|
Toy_freeValue(right);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void processLogical(Toy_VM* vm, Toy_OpcodeType opcode) {
|
static void processLogical(Toy_VM* vm, Toy_OpcodeType opcode) {
|
||||||
@@ -382,20 +446,29 @@ static void processJump(Toy_VM* vm) {
|
|||||||
case TOY_OP_PARAM_JUMP_IF_TRUE: {
|
case TOY_OP_PARAM_JUMP_IF_TRUE: {
|
||||||
Toy_Value value = Toy_popStack(&vm->stack);
|
Toy_Value value = Toy_popStack(&vm->stack);
|
||||||
if (Toy_checkValueIsTruthy(value) == true) {
|
if (Toy_checkValueIsTruthy(value) == true) {
|
||||||
Toy_freeValue(value);
|
if (TOY_VALUE_IS_REFERENCE(value) != true) {
|
||||||
|
Toy_freeValue(value);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Toy_freeValue(value);
|
|
||||||
|
if (TOY_VALUE_IS_REFERENCE(value) != true) {
|
||||||
|
Toy_freeValue(value);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_OP_PARAM_JUMP_IF_FALSE: {
|
case TOY_OP_PARAM_JUMP_IF_FALSE: {
|
||||||
Toy_Value value = Toy_popStack(&vm->stack);
|
Toy_Value value = Toy_popStack(&vm->stack);
|
||||||
if (Toy_checkValueIsTruthy(value) != true) {
|
if (Toy_checkValueIsTruthy(value) != true) {
|
||||||
Toy_freeValue(value);
|
if (TOY_VALUE_IS_REFERENCE(value) != true) {
|
||||||
|
Toy_freeValue(value);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Toy_freeValue(value);
|
if (TOY_VALUE_IS_REFERENCE(value) != true) {
|
||||||
|
Toy_freeValue(value);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -433,7 +506,7 @@ static void processAssert(Toy_VM* vm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//do the check
|
//do the check
|
||||||
if (TOY_VALUE_IS_NULL(value) || Toy_checkValueIsTruthy(value) == false) {
|
if (TOY_VALUE_IS_NULL(value) || Toy_checkValueIsTruthy(value) != true) {
|
||||||
//on a failure, print the message
|
//on a failure, print the message
|
||||||
Toy_String* string = Toy_stringifyValue(&vm->stringBucket, message);
|
Toy_String* string = Toy_stringifyValue(&vm->stringBucket, message);
|
||||||
char* buffer = Toy_getStringRawBuffer(string);
|
char* buffer = Toy_getStringRawBuffer(string);
|
||||||
@@ -446,8 +519,13 @@ static void processAssert(Toy_VM* vm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
Toy_freeValue(value);
|
if (TOY_VALUE_IS_REFERENCE(value) != true) {
|
||||||
Toy_freeValue(message);
|
Toy_freeValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TOY_VALUE_IS_REFERENCE(message) != true) {
|
||||||
|
Toy_freeValue(message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void processPrint(Toy_VM* vm) {
|
static void processPrint(Toy_VM* vm) {
|
||||||
@@ -460,7 +538,10 @@ static void processPrint(Toy_VM* vm) {
|
|||||||
|
|
||||||
free(buffer);
|
free(buffer);
|
||||||
Toy_freeString(string);
|
Toy_freeString(string);
|
||||||
Toy_freeValue(value);
|
|
||||||
|
if (TOY_VALUE_IS_REFERENCE(value) != true) {
|
||||||
|
Toy_freeValue(value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void processConcat(Toy_VM* vm) {
|
static void processConcat(Toy_VM* vm) {
|
||||||
@@ -469,6 +550,13 @@ static void processConcat(Toy_VM* vm) {
|
|||||||
|
|
||||||
if (!TOY_VALUE_IS_STRING(left) || !TOY_VALUE_IS_STRING(right)) {
|
if (!TOY_VALUE_IS_STRING(left) || !TOY_VALUE_IS_STRING(right)) {
|
||||||
Toy_error("Failed to concatenate a value that is not a string");
|
Toy_error("Failed to concatenate a value that is not a string");
|
||||||
|
|
||||||
|
if (TOY_VALUE_IS_REFERENCE(left) != true) {
|
||||||
|
Toy_freeValue(left);
|
||||||
|
}
|
||||||
|
if (TOY_VALUE_IS_REFERENCE(right) != true) {
|
||||||
|
Toy_freeValue(right);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -495,7 +583,7 @@ static void processIndex(Toy_VM* vm) {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Toy_error("Incorrect number of elements found in index");
|
Toy_error("Incorrect number of elements found in index");
|
||||||
//TODO: clear stack
|
//URGENT: clear stack, then leave null
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -504,26 +592,53 @@ static void processIndex(Toy_VM* vm) {
|
|||||||
//type checks
|
//type checks
|
||||||
if (!TOY_VALUE_IS_INTEGER(index)) {
|
if (!TOY_VALUE_IS_INTEGER(index)) {
|
||||||
Toy_error("Failed to index a string");
|
Toy_error("Failed to index a string");
|
||||||
Toy_freeValue(value);
|
if (TOY_VALUE_IS_REFERENCE(value) != true) {
|
||||||
Toy_freeValue(index);
|
Toy_freeValue(value);
|
||||||
Toy_freeValue(length);
|
}
|
||||||
|
if (TOY_VALUE_IS_REFERENCE(index) != true) {
|
||||||
|
Toy_freeValue(index);
|
||||||
|
}
|
||||||
|
if (TOY_VALUE_IS_REFERENCE(length) != true) {
|
||||||
|
Toy_freeValue(length);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(TOY_VALUE_IS_NULL(length) || TOY_VALUE_IS_INTEGER(length))) {
|
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 a string");
|
||||||
Toy_freeValue(value);
|
if (TOY_VALUE_IS_REFERENCE(value) != true) {
|
||||||
Toy_freeValue(index);
|
Toy_freeValue(value);
|
||||||
Toy_freeValue(length);
|
}
|
||||||
|
if (TOY_VALUE_IS_REFERENCE(index) != true) {
|
||||||
|
Toy_freeValue(index);
|
||||||
|
}
|
||||||
|
if (TOY_VALUE_IS_REFERENCE(length) != true) {
|
||||||
|
Toy_freeValue(length);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//extract values
|
//extract values
|
||||||
int i = TOY_VALUE_AS_INTEGER(index);
|
int i = TOY_VALUE_AS_INTEGER(index);
|
||||||
int l = TOY_VALUE_IS_INTEGER(length) ? TOY_VALUE_AS_INTEGER(length) : 1;
|
int l = TOY_VALUE_IS_INTEGER(length) ? TOY_VALUE_AS_INTEGER(length) : 1;
|
||||||
|
Toy_String* str = TOY_VALUE_AS_STRING(value);
|
||||||
|
|
||||||
|
//check indexing is within bounds
|
||||||
|
if ( (i < 0 || i >= str->length) || (i+l <= 0 || i+l > str->length)) {
|
||||||
|
Toy_error("String index is out of bounds");
|
||||||
|
if (TOY_VALUE_IS_REFERENCE(value) != true) {
|
||||||
|
Toy_freeValue(value);
|
||||||
|
}
|
||||||
|
if (TOY_VALUE_IS_REFERENCE(index) != true) {
|
||||||
|
Toy_freeValue(index);
|
||||||
|
}
|
||||||
|
if (TOY_VALUE_IS_REFERENCE(length) != true) {
|
||||||
|
Toy_freeValue(length);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//extract string
|
//extract string
|
||||||
Toy_String* str = TOY_VALUE_AS_STRING(value);
|
|
||||||
Toy_String* result = NULL;
|
Toy_String* result = NULL;
|
||||||
|
|
||||||
//extract cstring, based on type
|
//extract cstring, based on type
|
||||||
@@ -545,14 +660,83 @@ static void processIndex(Toy_VM* vm) {
|
|||||||
Toy_pushStack(&vm->stack, TOY_VALUE_FROM_STRING(result));
|
Toy_pushStack(&vm->stack, TOY_VALUE_FROM_STRING(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (TOY_VALUE_IS_ARRAY(value)) {
|
||||||
|
//type checks
|
||||||
|
if (!TOY_VALUE_IS_INTEGER(index)) {
|
||||||
|
Toy_error("Failed to index a string");
|
||||||
|
if (TOY_VALUE_IS_REFERENCE(value) != true) {
|
||||||
|
Toy_freeValue(value);
|
||||||
|
}
|
||||||
|
if (TOY_VALUE_IS_REFERENCE(index) != true) {
|
||||||
|
Toy_freeValue(index);
|
||||||
|
}
|
||||||
|
if (TOY_VALUE_IS_REFERENCE(length) != true) {
|
||||||
|
Toy_freeValue(length);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(TOY_VALUE_IS_NULL(length) || TOY_VALUE_IS_INTEGER(length))) {
|
||||||
|
Toy_error("Failed to index-length a string");
|
||||||
|
if (TOY_VALUE_IS_REFERENCE(value) != true) {
|
||||||
|
Toy_freeValue(value);
|
||||||
|
}
|
||||||
|
if (TOY_VALUE_IS_REFERENCE(index) != true) {
|
||||||
|
Toy_freeValue(index);
|
||||||
|
}
|
||||||
|
if (TOY_VALUE_IS_REFERENCE(length) != true) {
|
||||||
|
Toy_freeValue(length);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//extract values
|
||||||
|
int i = TOY_VALUE_AS_INTEGER(index);
|
||||||
|
int l = TOY_VALUE_IS_INTEGER(length) ? TOY_VALUE_AS_INTEGER(length) : 1;
|
||||||
|
Toy_Array* array = TOY_VALUE_AS_ARRAY(value);
|
||||||
|
|
||||||
|
//check indexing is within bounds
|
||||||
|
if ( (i < 0 || i >= array->count) || (i+l <= 0 || i+l > array->count)) {
|
||||||
|
Toy_error("Array index is out of bounds");
|
||||||
|
if (TOY_VALUE_IS_REFERENCE(value) != true) {
|
||||||
|
Toy_freeValue(value);
|
||||||
|
}
|
||||||
|
if (TOY_VALUE_IS_REFERENCE(index) != true) {
|
||||||
|
Toy_freeValue(index);
|
||||||
|
}
|
||||||
|
if (TOY_VALUE_IS_REFERENCE(length) != true) {
|
||||||
|
Toy_freeValue(length);
|
||||||
|
}
|
||||||
|
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(array->data[i]) || TOY_VALUE_IS_ARRAY(array->data[i])) {
|
||||||
|
//TODO: more types to be implemented
|
||||||
|
Toy_Value ref = TOY_REFERENCE_FROM_POINTER(&(array->data[i]));
|
||||||
|
|
||||||
|
Toy_pushStack(&vm->stack, ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
Toy_pushStack(&vm->stack, Toy_copyValue(array->data[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Unknown value type '%s' found in processIndex, exiting\n" TOY_CC_RESET, Toy_private_getValueTypeAsCString(value.type));
|
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);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Toy_freeValue(value);
|
if (TOY_VALUE_IS_REFERENCE(value) != true) {
|
||||||
Toy_freeValue(index);
|
Toy_freeValue(value);
|
||||||
Toy_freeValue(length);
|
}
|
||||||
|
if (TOY_VALUE_IS_REFERENCE(index) != true) {
|
||||||
|
Toy_freeValue(index);
|
||||||
|
}
|
||||||
|
if (TOY_VALUE_IS_REFERENCE(length) != true) {
|
||||||
|
Toy_freeValue(length);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void process(Toy_VM* vm) {
|
static void process(Toy_VM* vm) {
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ int test_sizeof_ast_64bit() {
|
|||||||
TEST_SIZEOF(Toy_AstBinary, 24);
|
TEST_SIZEOF(Toy_AstBinary, 24);
|
||||||
TEST_SIZEOF(Toy_AstCompare, 24);
|
TEST_SIZEOF(Toy_AstCompare, 24);
|
||||||
TEST_SIZEOF(Toy_AstGroup, 16);
|
TEST_SIZEOF(Toy_AstGroup, 16);
|
||||||
TEST_SIZEOF(Toy_AstCompound, 24);
|
TEST_SIZEOF(Toy_AstCompound, 16);
|
||||||
|
TEST_SIZEOF(Toy_AstAggregate, 24);
|
||||||
TEST_SIZEOF(Toy_AstAssert, 24);
|
TEST_SIZEOF(Toy_AstAssert, 24);
|
||||||
TEST_SIZEOF(Toy_AstIfThenElse, 32);
|
TEST_SIZEOF(Toy_AstIfThenElse, 32);
|
||||||
TEST_SIZEOF(Toy_AstWhileThen, 24);
|
TEST_SIZEOF(Toy_AstWhileThen, 24);
|
||||||
@@ -61,7 +62,8 @@ int test_sizeof_ast_32bit() {
|
|||||||
TEST_SIZEOF(Toy_AstBinary, 16);
|
TEST_SIZEOF(Toy_AstBinary, 16);
|
||||||
TEST_SIZEOF(Toy_AstCompare, 16);
|
TEST_SIZEOF(Toy_AstCompare, 16);
|
||||||
TEST_SIZEOF(Toy_AstGroup, 8);
|
TEST_SIZEOF(Toy_AstGroup, 8);
|
||||||
TEST_SIZEOF(Toy_AstCompound, 16);
|
TEST_SIZEOF(Toy_AstCompound, 12);
|
||||||
|
TEST_SIZEOF(Toy_AstAggregate, 16);
|
||||||
TEST_SIZEOF(Toy_AstAssert, 12);
|
TEST_SIZEOF(Toy_AstAssert, 12);
|
||||||
TEST_SIZEOF(Toy_AstIfThenElse, 16);
|
TEST_SIZEOF(Toy_AstIfThenElse, 16);
|
||||||
TEST_SIZEOF(Toy_AstWhileThen, 12);
|
TEST_SIZEOF(Toy_AstWhileThen, 12);
|
||||||
@@ -194,33 +196,33 @@ int test_type_emission(Toy_Bucket** bucketHandle) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//emit compound
|
//emit aggregate
|
||||||
{
|
{
|
||||||
//build the AST
|
//build the AST
|
||||||
Toy_Ast* ast = NULL;
|
Toy_Ast* ast = NULL;
|
||||||
Toy_Ast* right = NULL;
|
Toy_Ast* right = NULL;
|
||||||
Toy_private_emitAstValue(bucketHandle, &ast, TOY_VALUE_FROM_INTEGER(42));
|
Toy_private_emitAstValue(bucketHandle, &ast, TOY_VALUE_FROM_INTEGER(42));
|
||||||
Toy_private_emitAstValue(bucketHandle, &right, TOY_VALUE_FROM_INTEGER(69));
|
Toy_private_emitAstValue(bucketHandle, &right, TOY_VALUE_FROM_INTEGER(69));
|
||||||
Toy_private_emitAstCompound(bucketHandle, &ast, TOY_AST_FLAG_COMPOUND_COLLECTION, right);
|
Toy_private_emitAstAggregate(bucketHandle, &ast, TOY_AST_FLAG_COLLECTION, right);
|
||||||
|
|
||||||
//check if it worked
|
//check if it worked
|
||||||
if (
|
if (
|
||||||
ast == NULL ||
|
ast == NULL ||
|
||||||
ast->type != TOY_AST_COMPOUND ||
|
ast->type != TOY_AST_AGGREGATE ||
|
||||||
|
|
||||||
ast->compound.left == NULL ||
|
ast->aggregate.left == NULL ||
|
||||||
ast->compound.left->type != TOY_AST_VALUE ||
|
ast->aggregate.left->type != TOY_AST_VALUE ||
|
||||||
TOY_VALUE_IS_INTEGER(ast->compound.left->value.value) != true ||
|
TOY_VALUE_IS_INTEGER(ast->aggregate.left->value.value) != true ||
|
||||||
TOY_VALUE_AS_INTEGER(ast->compound.left->value.value) != 42 ||
|
TOY_VALUE_AS_INTEGER(ast->aggregate.left->value.value) != 42 ||
|
||||||
|
|
||||||
ast->compound.right == NULL ||
|
ast->aggregate.right == NULL ||
|
||||||
ast->compound.right->type != TOY_AST_VALUE ||
|
ast->aggregate.right->type != TOY_AST_VALUE ||
|
||||||
TOY_VALUE_IS_INTEGER(ast->compound.right->value.value) != true ||
|
TOY_VALUE_IS_INTEGER(ast->aggregate.right->value.value) != true ||
|
||||||
TOY_VALUE_AS_INTEGER(ast->compound.right->value.value) != 69 ||
|
TOY_VALUE_AS_INTEGER(ast->aggregate.right->value.value) != 69 ||
|
||||||
|
|
||||||
false)
|
false)
|
||||||
{
|
{
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to emit a compound as 'Toy_Ast', state unknown\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to emit an aggregate as 'Toy_Ast', state unknown\n" TOY_CC_RESET);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -455,7 +455,7 @@ int test_binary(Toy_Bucket** bucketHandle) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int test_compound(Toy_Bucket** bucketHandle) {
|
int test_aggregate(Toy_Bucket** bucketHandle) {
|
||||||
//test collections (do it first, because it's used below)
|
//test collections (do it first, because it's used below)
|
||||||
{
|
{
|
||||||
char* source = "1, 2, 3;";
|
char* source = "1, 2, 3;";
|
||||||
@@ -467,27 +467,27 @@ int test_compound(Toy_Bucket** bucketHandle) {
|
|||||||
ast->type != TOY_AST_BLOCK ||
|
ast->type != TOY_AST_BLOCK ||
|
||||||
ast->block.child == NULL ||
|
ast->block.child == NULL ||
|
||||||
|
|
||||||
ast->block.child->type != TOY_AST_COMPOUND ||
|
ast->block.child->type != TOY_AST_AGGREGATE ||
|
||||||
ast->block.child->compound.flag != TOY_AST_FLAG_COMPOUND_COLLECTION ||
|
ast->block.child->aggregate.flag != TOY_AST_FLAG_COLLECTION ||
|
||||||
|
|
||||||
ast->block.child->compound.left == NULL ||
|
ast->block.child->aggregate.left == NULL ||
|
||||||
ast->block.child->compound.left->type != TOY_AST_VALUE ||
|
ast->block.child->aggregate.left->type != TOY_AST_VALUE ||
|
||||||
TOY_VALUE_IS_INTEGER(ast->block.child->compound.left->value.value) != true ||
|
TOY_VALUE_IS_INTEGER(ast->block.child->aggregate.left->value.value) != true ||
|
||||||
TOY_VALUE_AS_INTEGER(ast->block.child->compound.left->value.value) != 1 ||
|
TOY_VALUE_AS_INTEGER(ast->block.child->aggregate.left->value.value) != 1 ||
|
||||||
|
|
||||||
ast->block.child->compound.right == NULL ||
|
ast->block.child->aggregate.right == NULL ||
|
||||||
ast->block.child->compound.right->type != TOY_AST_COMPOUND ||
|
ast->block.child->aggregate.right->type != TOY_AST_AGGREGATE ||
|
||||||
ast->block.child->compound.right->compound.flag != TOY_AST_FLAG_COMPOUND_COLLECTION ||
|
ast->block.child->aggregate.right->aggregate.flag != TOY_AST_FLAG_COLLECTION ||
|
||||||
|
|
||||||
ast->block.child->compound.right->compound.left == NULL ||
|
ast->block.child->aggregate.right->aggregate.left == NULL ||
|
||||||
ast->block.child->compound.right->compound.left->type != TOY_AST_VALUE ||
|
ast->block.child->aggregate.right->aggregate.left->type != TOY_AST_VALUE ||
|
||||||
TOY_VALUE_IS_INTEGER(ast->block.child->compound.right->compound.left->value.value) != true ||
|
TOY_VALUE_IS_INTEGER(ast->block.child->aggregate.right->aggregate.left->value.value) != true ||
|
||||||
TOY_VALUE_AS_INTEGER(ast->block.child->compound.right->compound.left->value.value) != 2 ||
|
TOY_VALUE_AS_INTEGER(ast->block.child->aggregate.right->aggregate.left->value.value) != 2 ||
|
||||||
|
|
||||||
ast->block.child->compound.right->compound.right == NULL ||
|
ast->block.child->aggregate.right->aggregate.right == NULL ||
|
||||||
ast->block.child->compound.right->compound.right->type != TOY_AST_VALUE ||
|
ast->block.child->aggregate.right->aggregate.right->type != TOY_AST_VALUE ||
|
||||||
TOY_VALUE_IS_INTEGER(ast->block.child->compound.right->compound.right->value.value) != true ||
|
TOY_VALUE_IS_INTEGER(ast->block.child->aggregate.right->aggregate.right->value.value) != true ||
|
||||||
TOY_VALUE_AS_INTEGER(ast->block.child->compound.right->compound.right->value.value) != 3 ||
|
TOY_VALUE_AS_INTEGER(ast->block.child->aggregate.right->aggregate.right->value.value) != 3 ||
|
||||||
|
|
||||||
false)
|
false)
|
||||||
{
|
{
|
||||||
@@ -507,17 +507,17 @@ int test_compound(Toy_Bucket** bucketHandle) {
|
|||||||
ast->type != TOY_AST_BLOCK ||
|
ast->type != TOY_AST_BLOCK ||
|
||||||
ast->block.child == NULL ||
|
ast->block.child == NULL ||
|
||||||
|
|
||||||
ast->block.child->type != TOY_AST_COMPOUND ||
|
ast->block.child->type != TOY_AST_AGGREGATE ||
|
||||||
ast->block.child->compound.flag != TOY_AST_FLAG_COMPOUND_INDEX ||
|
ast->block.child->aggregate.flag != TOY_AST_FLAG_INDEX ||
|
||||||
|
|
||||||
ast->block.child->compound.left == NULL ||
|
ast->block.child->aggregate.left == NULL ||
|
||||||
ast->block.child->compound.left->type != TOY_AST_VAR_ACCESS ||
|
ast->block.child->aggregate.left->type != TOY_AST_VAR_ACCESS ||
|
||||||
ast->block.child->compound.left->varAccess.name->type != TOY_STRING_NAME ||
|
ast->block.child->aggregate.left->varAccess.name->type != TOY_STRING_NAME ||
|
||||||
strcmp(ast->block.child->compound.left->varAccess.name->as.name.data, "name") != 0 ||
|
strcmp(ast->block.child->aggregate.left->varAccess.name->as.name.data, "name") != 0 ||
|
||||||
|
|
||||||
ast->block.child->compound.right->type != TOY_AST_VALUE ||
|
ast->block.child->aggregate.right->type != TOY_AST_VALUE ||
|
||||||
TOY_VALUE_IS_INTEGER(ast->block.child->compound.right->value.value) != true ||
|
TOY_VALUE_IS_INTEGER(ast->block.child->aggregate.right->value.value) != true ||
|
||||||
TOY_VALUE_AS_INTEGER(ast->block.child->compound.right->value.value) != 0 ||
|
TOY_VALUE_AS_INTEGER(ast->block.child->aggregate.right->value.value) != 0 ||
|
||||||
|
|
||||||
false)
|
false)
|
||||||
{
|
{
|
||||||
@@ -537,23 +537,23 @@ int test_compound(Toy_Bucket** bucketHandle) {
|
|||||||
ast->type != TOY_AST_BLOCK ||
|
ast->type != TOY_AST_BLOCK ||
|
||||||
ast->block.child == NULL ||
|
ast->block.child == NULL ||
|
||||||
|
|
||||||
ast->block.child->type != TOY_AST_COMPOUND ||
|
ast->block.child->type != TOY_AST_AGGREGATE ||
|
||||||
ast->block.child->compound.flag != TOY_AST_FLAG_COMPOUND_INDEX ||
|
ast->block.child->aggregate.flag != TOY_AST_FLAG_INDEX ||
|
||||||
|
|
||||||
ast->block.child->compound.left == NULL ||
|
ast->block.child->aggregate.left == NULL ||
|
||||||
ast->block.child->compound.left->type != TOY_AST_VAR_ACCESS ||
|
ast->block.child->aggregate.left->type != TOY_AST_VAR_ACCESS ||
|
||||||
ast->block.child->compound.left->varAccess.name->type != TOY_STRING_NAME ||
|
ast->block.child->aggregate.left->varAccess.name->type != TOY_STRING_NAME ||
|
||||||
strcmp(ast->block.child->compound.left->varAccess.name->as.name.data, "name") != 0 ||
|
strcmp(ast->block.child->aggregate.left->varAccess.name->as.name.data, "name") != 0 ||
|
||||||
|
|
||||||
ast->block.child->compound.right->type != TOY_AST_COMPOUND ||
|
ast->block.child->aggregate.right->type != TOY_AST_AGGREGATE ||
|
||||||
ast->block.child->compound.right->compound.flag != TOY_AST_FLAG_COMPOUND_COLLECTION ||
|
ast->block.child->aggregate.right->aggregate.flag != TOY_AST_FLAG_COLLECTION ||
|
||||||
ast->block.child->compound.right->compound.left->type != TOY_AST_VALUE ||
|
ast->block.child->aggregate.right->aggregate.left->type != TOY_AST_VALUE ||
|
||||||
|
|
||||||
TOY_VALUE_IS_INTEGER(ast->block.child->compound.right->compound.left->value.value) != true ||
|
TOY_VALUE_IS_INTEGER(ast->block.child->aggregate.right->aggregate.left->value.value) != true ||
|
||||||
TOY_VALUE_AS_INTEGER(ast->block.child->compound.right->compound.left->value.value) != 0 ||
|
TOY_VALUE_AS_INTEGER(ast->block.child->aggregate.right->aggregate.left->value.value) != 0 ||
|
||||||
|
|
||||||
TOY_VALUE_IS_INTEGER(ast->block.child->compound.right->compound.right->value.value) != true ||
|
TOY_VALUE_IS_INTEGER(ast->block.child->aggregate.right->aggregate.right->value.value) != true ||
|
||||||
TOY_VALUE_AS_INTEGER(ast->block.child->compound.right->compound.right->value.value) != 1 ||
|
TOY_VALUE_AS_INTEGER(ast->block.child->aggregate.right->aggregate.right->value.value) != 1 ||
|
||||||
|
|
||||||
false)
|
false)
|
||||||
{
|
{
|
||||||
@@ -927,7 +927,7 @@ int main() {
|
|||||||
|
|
||||||
{
|
{
|
||||||
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||||
res = test_compound(&bucket);
|
res = test_aggregate(&bucket);
|
||||||
Toy_freeBucket(&bucket);
|
Toy_freeBucket(&bucket);
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||||
|
|||||||
@@ -329,7 +329,7 @@ int test_scope_elements() {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Toy_Value result = Toy_accessScope(scope, hello2);
|
Toy_Value* result = Toy_accessScopeAsPointer(scope, hello2);
|
||||||
|
|
||||||
//check integer
|
//check integer
|
||||||
if (scope == NULL ||
|
if (scope == NULL ||
|
||||||
@@ -338,8 +338,8 @@ int test_scope_elements() {
|
|||||||
scope->table->capacity != 8 ||
|
scope->table->capacity != 8 ||
|
||||||
scope->refCount != 1 ||
|
scope->refCount != 1 ||
|
||||||
|
|
||||||
TOY_VALUE_IS_INTEGER(result) != true ||
|
TOY_VALUE_IS_INTEGER(*result) != true ||
|
||||||
TOY_VALUE_AS_INTEGER(result) != 42 ||
|
TOY_VALUE_AS_INTEGER(*result) != 42 ||
|
||||||
|
|
||||||
false)
|
false)
|
||||||
{
|
{
|
||||||
@@ -354,7 +354,7 @@ int test_scope_elements() {
|
|||||||
//assign values
|
//assign values
|
||||||
Toy_assignScope(scope, hello1, TOY_VALUE_FROM_FLOAT(3.1415f));
|
Toy_assignScope(scope, hello1, TOY_VALUE_FROM_FLOAT(3.1415f));
|
||||||
|
|
||||||
Toy_Value resultTwo = Toy_accessScope(scope, hello2);
|
Toy_Value* resultTwo = Toy_accessScopeAsPointer(scope, hello2);
|
||||||
|
|
||||||
//check float
|
//check float
|
||||||
if (scope == NULL ||
|
if (scope == NULL ||
|
||||||
@@ -363,8 +363,8 @@ int test_scope_elements() {
|
|||||||
scope->table->capacity != 8 ||
|
scope->table->capacity != 8 ||
|
||||||
scope->refCount != 1 ||
|
scope->refCount != 1 ||
|
||||||
|
|
||||||
TOY_VALUE_IS_FLOAT(resultTwo) != true ||
|
TOY_VALUE_IS_FLOAT(*resultTwo) != true ||
|
||||||
TOY_VALUE_AS_FLOAT(resultTwo) != 3.1415f ||
|
TOY_VALUE_AS_FLOAT(*resultTwo) != 3.1415f ||
|
||||||
|
|
||||||
false)
|
false)
|
||||||
{
|
{
|
||||||
@@ -399,10 +399,10 @@ int test_scope_elements() {
|
|||||||
|
|
||||||
{
|
{
|
||||||
//check it's accessible
|
//check it's accessible
|
||||||
Toy_Value result1 = Toy_accessScope(scope, hello);
|
Toy_Value* result1 = Toy_accessScopeAsPointer(scope, hello);
|
||||||
|
|
||||||
if (TOY_VALUE_IS_INTEGER(result1) != true ||
|
if (TOY_VALUE_IS_INTEGER(*result1) != true ||
|
||||||
TOY_VALUE_AS_INTEGER(result1) != 42)
|
TOY_VALUE_AS_INTEGER(*result1) != 42)
|
||||||
{
|
{
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to access from an ancestor Toy_Scope\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to access from an ancestor Toy_Scope\n" TOY_CC_RESET);
|
||||||
Toy_freeString(hello);
|
Toy_freeString(hello);
|
||||||
@@ -416,10 +416,10 @@ int test_scope_elements() {
|
|||||||
|
|
||||||
{
|
{
|
||||||
//check it's shadowed correctly
|
//check it's shadowed correctly
|
||||||
Toy_Value result2 = Toy_accessScope(scope, hello);
|
Toy_Value* result2 = Toy_accessScopeAsPointer(scope, hello);
|
||||||
|
|
||||||
if (TOY_VALUE_IS_FLOAT(result2) != true ||
|
if (TOY_VALUE_IS_FLOAT(*result2) != true ||
|
||||||
TOY_VALUE_AS_FLOAT(result2) != 3.1415f)
|
TOY_VALUE_AS_FLOAT(*result2) != 3.1415f)
|
||||||
{
|
{
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to shadow an entry in Toy_Scope\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to shadow an entry in Toy_Scope\n" TOY_CC_RESET);
|
||||||
Toy_freeString(hello);
|
Toy_freeString(hello);
|
||||||
@@ -433,10 +433,10 @@ int test_scope_elements() {
|
|||||||
|
|
||||||
{
|
{
|
||||||
//check it's recovered correctly
|
//check it's recovered correctly
|
||||||
Toy_Value result3 = Toy_accessScope(scope, hello);
|
Toy_Value* result3 = Toy_accessScopeAsPointer(scope, hello);
|
||||||
|
|
||||||
if (TOY_VALUE_IS_INTEGER(result3) != true ||
|
if (TOY_VALUE_IS_INTEGER(*result3) != true ||
|
||||||
TOY_VALUE_AS_INTEGER(result3) != 42)
|
TOY_VALUE_AS_INTEGER(*result3) != 42)
|
||||||
{
|
{
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to recover an entry in Toy_Scope\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to recover an entry in Toy_Scope\n" TOY_CC_RESET);
|
||||||
Toy_freeString(hello);
|
Toy_freeString(hello);
|
||||||
@@ -450,10 +450,10 @@ int test_scope_elements() {
|
|||||||
|
|
||||||
{
|
{
|
||||||
//check it's assigned correctly
|
//check it's assigned correctly
|
||||||
Toy_Value result4 = Toy_accessScope(scope, hello);
|
Toy_Value* result4 = Toy_accessScopeAsPointer(scope, hello);
|
||||||
|
|
||||||
if (TOY_VALUE_IS_INTEGER(result4) != true ||
|
if (TOY_VALUE_IS_INTEGER(*result4) != true ||
|
||||||
TOY_VALUE_AS_INTEGER(result4) != 8891)
|
TOY_VALUE_AS_INTEGER(*result4) != 8891)
|
||||||
{
|
{
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to assign to an ancestor in Toy_Scope\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to assign to an ancestor in Toy_Scope\n" TOY_CC_RESET);
|
||||||
Toy_freeString(hello);
|
Toy_freeString(hello);
|
||||||
@@ -467,10 +467,10 @@ int test_scope_elements() {
|
|||||||
|
|
||||||
{
|
{
|
||||||
//check it's in the correct state
|
//check it's in the correct state
|
||||||
Toy_Value result5 = Toy_accessScope(scope, hello);
|
Toy_Value* result5 = Toy_accessScopeAsPointer(scope, hello);
|
||||||
|
|
||||||
if (TOY_VALUE_IS_INTEGER(result5) != true ||
|
if (TOY_VALUE_IS_INTEGER(*result5) != true ||
|
||||||
TOY_VALUE_AS_INTEGER(result5) != 8891)
|
TOY_VALUE_AS_INTEGER(*result5) != 8891)
|
||||||
{
|
{
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to access an altered entry of an ancestor in Toy_Scope\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to access an altered entry of an ancestor in Toy_Scope\n" TOY_CC_RESET);
|
||||||
Toy_freeString(hello);
|
Toy_freeString(hello);
|
||||||
|
|||||||
@@ -663,8 +663,8 @@ int test_scope(Toy_Bucket** bucketHandle) {
|
|||||||
|
|
||||||
vm.scope == NULL ||
|
vm.scope == NULL ||
|
||||||
Toy_isDeclaredScope(vm.scope, key) == false ||
|
Toy_isDeclaredScope(vm.scope, key) == false ||
|
||||||
TOY_VALUE_IS_INTEGER(Toy_accessScope(vm.scope, key)) != true ||
|
TOY_VALUE_IS_INTEGER(*Toy_accessScopeAsPointer(vm.scope, key)) != true ||
|
||||||
TOY_VALUE_AS_INTEGER(Toy_accessScope(vm.scope, key)) != 42
|
TOY_VALUE_AS_INTEGER(*Toy_accessScopeAsPointer(vm.scope, key)) != 42
|
||||||
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@@ -712,7 +712,7 @@ int test_scope(Toy_Bucket** bucketHandle) {
|
|||||||
|
|
||||||
vm.scope == NULL ||
|
vm.scope == NULL ||
|
||||||
Toy_isDeclaredScope(vm.scope, key) == false ||
|
Toy_isDeclaredScope(vm.scope, key) == false ||
|
||||||
TOY_VALUE_IS_NULL(Toy_accessScope(vm.scope, key)) != true
|
TOY_VALUE_IS_NULL(*Toy_accessScopeAsPointer(vm.scope, key)) != true
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Unexpected result in 'Toy_VM' when testing scope, source: %s\n" TOY_CC_RESET, source);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Unexpected result in 'Toy_VM' when testing scope, source: %s\n" TOY_CC_RESET, source);
|
||||||
|
|||||||
Reference in New Issue
Block a user