Added 'Toy_String' to 'Toy_Value' structure, read more

To help with storing strings within tables, I've replaced the unused
'_padding' member of 'Toy_String' with 'cachedHash', which is set to
zero on string allocation.

The hash of a string isn't generated and stored until it's actually
needed, as the rope pattern means not every string needs a hash -
hopefully this will save unnecessarily wasted time.

When a hash of a string is needed, the hashing function first checks to
see if that string already has one, and if so, returns it. Again, less
time wasted.

When generating a new string hash, the hashing function takes the
string's type into account, as node-based strings first need their
contents assembled into a simple char buffer.

Other changes include:

* Changed 'TOY_VALUE_TO_*' to 'TOY_VALUE_FROM_*'
* Changed 'TOY_VALUE_IS_EQUAL' to 'TOY_VALUES_ARE_EQUAL'
* Added a missing '#pragma once' to 'toy_print.h'
This commit is contained in:
2024-10-07 17:20:08 +11:00
parent d62ee2a9a3
commit 14653a303f
25 changed files with 266 additions and 175 deletions

View File

@@ -3,6 +3,7 @@
//general utilities
#include "toy_common.h"
#include "toy_console_colors.h"
#include "toy_print.h"
//basic structures
#include "toy_value.h"
@@ -21,3 +22,4 @@
#include "toy_parser.h"
#include "toy_bytecode.h"
#include "toy_vm.h"

View File

@@ -130,4 +130,5 @@ void Toy_private_emitAstPrint(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);
void Toy_private_emitAstPass(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);
void Toy_private_emitAstError(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);
void Toy_private_emitAstEnd(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);
void Toy_private_emitAstEnd(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);

View File

@@ -11,3 +11,4 @@ typedef struct Toy_Bytecode {
TOY_API Toy_Bytecode Toy_compileBytecode(Toy_Ast* ast);
TOY_API void Toy_freeBytecode(Toy_Bytecode bc);

View File

@@ -75,3 +75,4 @@ NOTE: you need both font AND background for these to work
#define TOY_CC_RESET
#endif

View File

@@ -13,3 +13,4 @@ extern const Toy_KeywordTypeTuple Toy_private_keywords[];
//access
const char* Toy_private_findKeywordByType(const Toy_TokenType type);
Toy_TokenType Toy_private_findTypeByKeyword(const char* keyword);

View File

@@ -1,7 +1,7 @@
#pragma once
#include "toy_token_types.h"
#include "toy_common.h"
#include "toy_token_types.h"
//lexers are bound to a string of code
typedef struct {
@@ -25,3 +25,4 @@ TOY_API void Toy_private_printToken(Toy_Token* token); //debugging
//util
#define TOY_BLANK_TOKEN() ((Toy_Token){TOY_TOKEN_NULL, 0, 0, NULL})

View File

@@ -42,3 +42,4 @@ typedef enum Toy_OpcodeType {
TOY_OPCODE_ERROR,
TOY_OPCODE_EOF = 255,
} Toy_OpcodeType;

View File

@@ -217,15 +217,15 @@ static ParsingTuple parsingRulesetTable[] = {
static Toy_AstFlag atomic(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {
switch(parser->previous.type) {
case TOY_TOKEN_NULL:
Toy_private_emitAstValue(bucketHandle, rootHandle, TOY_VALUE_TO_NULL());
Toy_private_emitAstValue(bucketHandle, rootHandle, TOY_VALUE_FROM_NULL());
return TOY_AST_FLAG_NONE;
case TOY_TOKEN_LITERAL_TRUE:
Toy_private_emitAstValue(bucketHandle, rootHandle, TOY_VALUE_TO_BOOLEAN(true));
Toy_private_emitAstValue(bucketHandle, rootHandle, TOY_VALUE_FROM_BOOLEAN(true));
return TOY_AST_FLAG_NONE;
case TOY_TOKEN_LITERAL_FALSE:
Toy_private_emitAstValue(bucketHandle, rootHandle, TOY_VALUE_TO_BOOLEAN(false));
Toy_private_emitAstValue(bucketHandle, rootHandle, TOY_VALUE_FROM_BOOLEAN(false));
return TOY_AST_FLAG_NONE;
case TOY_TOKEN_LITERAL_INTEGER: {
@@ -241,7 +241,7 @@ static Toy_AstFlag atomic(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast
int value = 0;
sscanf(buffer, "%d", &value);
Toy_private_emitAstValue(bucketHandle, rootHandle, TOY_VALUE_TO_INTEGER(value));
Toy_private_emitAstValue(bucketHandle, rootHandle, TOY_VALUE_FROM_INTEGER(value));
return TOY_AST_FLAG_NONE;
}
@@ -258,7 +258,7 @@ static Toy_AstFlag atomic(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast
float value = 0;
sscanf(buffer, "%f", &value);
Toy_private_emitAstValue(bucketHandle, rootHandle, TOY_VALUE_TO_FLOAT(value));
Toy_private_emitAstValue(bucketHandle, rootHandle, TOY_VALUE_FROM_FLOAT(value));
return TOY_AST_FLAG_NONE;
}
@@ -280,10 +280,10 @@ static Toy_AstFlag unary(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast*
//negative numbers
if ((*rootHandle)->type == TOY_AST_VALUE && TOY_VALUE_IS_INTEGER((*rootHandle)->value.value) && connectedDigit) {
(*rootHandle)->value.value = TOY_VALUE_TO_INTEGER( -TOY_VALUE_AS_INTEGER((*rootHandle)->value.value) );
(*rootHandle)->value.value = TOY_VALUE_FROM_INTEGER( -TOY_VALUE_AS_INTEGER((*rootHandle)->value.value) );
}
else if ((*rootHandle)->type == TOY_AST_VALUE && TOY_VALUE_IS_FLOAT((*rootHandle)->value.value) && connectedDigit) {
(*rootHandle)->value.value = TOY_VALUE_TO_FLOAT( -TOY_VALUE_AS_FLOAT((*rootHandle)->value.value) );
(*rootHandle)->value.value = TOY_VALUE_FROM_FLOAT( -TOY_VALUE_AS_FLOAT((*rootHandle)->value.value) );
}
else {
//actually emit the negation node
@@ -296,7 +296,7 @@ static Toy_AstFlag unary(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast*
//inverted booleans
if ((*rootHandle)->type == TOY_AST_VALUE && TOY_VALUE_IS_BOOLEAN((*rootHandle)->value.value)) {
(*rootHandle)->value.value = TOY_VALUE_TO_BOOLEAN( !TOY_VALUE_AS_BOOLEAN((*rootHandle)->value.value) );
(*rootHandle)->value.value = TOY_VALUE_FROM_BOOLEAN( !TOY_VALUE_AS_BOOLEAN((*rootHandle)->value.value) );
}
else {
//actually emit the negation node

View File

@@ -19,3 +19,4 @@ typedef struct Toy_Parser {
TOY_API void Toy_bindParser(Toy_Parser* parser, Toy_Lexer* lexer);
TOY_API Toy_Ast* Toy_scanParser(Toy_Bucket** bucketHandle, Toy_Parser* parser);
TOY_API void Toy_resetParser(Toy_Parser* parser);

View File

@@ -1,3 +1,5 @@
#pragma once
#include "toy_common.h"
//handle callbacks for printing to the terminal, or elsewhere

View File

@@ -27,3 +27,4 @@ typedef struct Toy_Routine {
} Toy_Routine;
TOY_API void* Toy_compileRoutine(Toy_Ast* ast);

View File

@@ -15,3 +15,4 @@ TOY_API void Toy_freeStack(Toy_Stack* stack);
TOY_API void Toy_pushStack(Toy_Stack** stackHandle, Toy_Value value);
TOY_API Toy_Value Toy_peekStack(Toy_Stack** stackHandle);
TOY_API Toy_Value Toy_popStack(Toy_Stack** stackHandle);

View File

@@ -47,6 +47,7 @@ Toy_String* Toy_createStringLength(Toy_Bucket** bucketHandle, const char* cstrin
ret->type = TOY_STRING_LEAF;
ret->length = length;
ret->refCount = 1;
ret->cachedHash = 0; //don't calc until needed
memcpy(ret->as.leaf.data, cstring, length);
ret->as.leaf.data[length] = '\0';
@@ -61,6 +62,7 @@ TOY_API Toy_String* Toy_createNameString(Toy_Bucket** bucketHandle, const char*
ret->type = TOY_STRING_NAME;
ret->length = length;
ret->refCount = 1;
ret->cachedHash = 0; //don't calc until needed
memcpy(ret->as.name.data, cname, length);
ret->as.name.data[length] = '\0';
@@ -87,6 +89,7 @@ Toy_String* Toy_deepCopyString(Toy_Bucket** bucketHandle, Toy_String* str) {
ret->type = TOY_STRING_LEAF;
ret->length = str->length;
ret->refCount = 1;
ret->cachedHash = str->cachedHash;
deepCopyUtil(ret->as.leaf.data, str); //copy each leaf into the buffer
ret->as.leaf.data[ret->length] = '\0';
}
@@ -94,6 +97,7 @@ Toy_String* Toy_deepCopyString(Toy_Bucket** bucketHandle, Toy_String* str) {
ret->type = TOY_STRING_NAME;
ret->length = str->length;
ret->refCount = 1;
ret->cachedHash = str->cachedHash;
memcpy(ret->as.name.data, str->as.name.data, str->length);
ret->as.name.data[ret->length] = '\0';
}
@@ -117,6 +121,7 @@ Toy_String* Toy_concatStrings(Toy_Bucket** bucketHandle, Toy_String* left, Toy_S
ret->type = TOY_STRING_NODE;
ret->length = left->length + right->length;
ret->refCount = 1;
ret->cachedHash = 0; //don't calc until needed
ret->as.node.left = left;
ret->as.node.right = right;
@@ -250,4 +255,4 @@ int Toy_compareStrings(Toy_String* left, Toy_String* right) {
const char* rightHead = NULL;
return deepCompareUtil(left, right, &leftHead, &rightHead);
}
}

View File

@@ -1,3 +1,5 @@
#pragma once
#include "toy_common.h"
#include "toy_bucket.h"
@@ -13,8 +15,7 @@ typedef struct Toy_String { //32 | 64 BITNESS
unsigned int length; //4 | 4
unsigned int refCount; //4 | 4
int _padding; //4 | 4
unsigned int cachedHash; //4 | 4
union {
struct {
@@ -52,3 +53,4 @@ TOY_API int Toy_getStringRefCount(Toy_String* str);
TOY_API char* Toy_getStringRawBuffer(Toy_String* str); //allocates the buffer on the heap, needs to be freed
TOY_API int Toy_compareStrings(Toy_String* left, Toy_String* right); //return value mimics strcmp()

View File

@@ -18,7 +18,7 @@ static void probeAndInsert(Toy_Table** tableHandle, Toy_Value key, Toy_Value val
//probe
while (true) {
//if we're overriding an existing value
if (TOY_VALUE_IS_EQUAL((*tableHandle)->data[probe].key, key)) {
if (TOY_VALUES_ARE_EQUAL((*tableHandle)->data[probe].key, key)) {
(*tableHandle)->data[probe] = entry;
//TODO: benchmark the psl optimisation
@@ -120,13 +120,13 @@ Toy_Value Toy_lookupTable(Toy_Table** tableHandle, Toy_Value key) {
while (true) {
//found the entry
if (TOY_VALUE_IS_EQUAL((*tableHandle)->data[probe].key, key)) {
if (TOY_VALUES_ARE_EQUAL((*tableHandle)->data[probe].key, key)) {
return (*tableHandle)->data[probe].value;
}
//if its an empty slot
if (TOY_VALUE_IS_NULL((*tableHandle)->data[probe].key)) {
return TOY_VALUE_TO_NULL();
return TOY_VALUE_FROM_NULL();
}
//adjust and continue
@@ -145,7 +145,7 @@ void Toy_removeTable(Toy_Table** tableHandle, Toy_Value key) {
while (true) {
//found the entry
if (TOY_VALUE_IS_EQUAL((*tableHandle)->data[probe].key, key)) {
if (TOY_VALUES_ARE_EQUAL((*tableHandle)->data[probe].key, key)) {
break;
}
@@ -174,6 +174,6 @@ void Toy_removeTable(Toy_Table** tableHandle, Toy_Value key) {
}
//finally, wipe the removed entry
(*tableHandle)->data[wipe] = (Toy_TableEntry){ .key = TOY_VALUE_TO_NULL(), .value = TOY_VALUE_TO_NULL(), .psl = 0 };
(*tableHandle)->data[wipe] = (Toy_TableEntry){ .key = TOY_VALUE_FROM_NULL(), .value = TOY_VALUE_FROM_NULL(), .psl = 0 };
(*tableHandle)->count--;
}

View File

@@ -25,3 +25,4 @@ TOY_API void Toy_freeTable(Toy_Table* table);
TOY_API void Toy_insertTable(Toy_Table** tableHandle, Toy_Value key, Toy_Value value);
TOY_API Toy_Value Toy_lookupTable(Toy_Table** tableHandle, Toy_Value key);
TOY_API void Toy_removeTable(Toy_Table** tableHandle, Toy_Value key);

View File

@@ -106,3 +106,4 @@ typedef enum Toy_TokenType {
TOY_TOKEN_ERROR,
TOY_TOKEN_EOF,
} Toy_TokenType;

View File

@@ -1,8 +1,11 @@
#include "toy_value.h"
#include "toy_console_colors.h"
#include "toy_print.h"
#include "toy_string.h"
#include <stdio.h>
#include <stdlib.h>
bool Toy_private_isTruthy(Toy_Value value) {
//null is an error
@@ -21,7 +24,7 @@ bool Toy_private_isTruthy(Toy_Value value) {
bool Toy_private_isEqual(Toy_Value left, Toy_Value right) {
//temp check
if (right.type > TOY_VALUE_FLOAT) {
if (right.type > TOY_VALUE_STRING) {
Toy_error(TOY_CC_ERROR "ERROR: Unknown types in value equality comparison\n" TOY_CC_RESET); //TODO: varargs
}
@@ -51,6 +54,11 @@ bool Toy_private_isEqual(Toy_Value left, Toy_Value right) {
return false;
case TOY_VALUE_STRING:
if (TOY_VALUE_IS_STRING(right)) {
return Toy_compareStrings(TOY_VALUE_AS_STRING(left), TOY_VALUE_AS_STRING(right)) == 0;
}
return false;
case TOY_VALUE_ARRAY:
case TOY_VALUE_DICTIONARY:
case TOY_VALUE_FUNCTION:
@@ -96,7 +104,28 @@ unsigned int Toy_hashValue(Toy_Value value) {
case TOY_VALUE_FLOAT:
return hashUInt( *((int*)(&TOY_VALUE_AS_FLOAT(value))) );
case TOY_VALUE_STRING:
case TOY_VALUE_STRING: {
Toy_String* str = TOY_VALUE_AS_STRING(value);
if (str->cachedHash != 0) {
return str->cachedHash;
}
else if (str->type == TOY_STRING_NODE) {
//TODO: I wonder it it would be possible to discretely swap the composite node string with a new leaf string here? Would that speed up other parts of the code by not having to walk the tree?
char* buffer = Toy_getStringRawBuffer(str);
str->cachedHash = hashCString(buffer);
free(buffer);
}
else if (str->type == TOY_STRING_LEAF) {
str->cachedHash = hashCString(str->as.leaf.data);
}
else if (str->type == TOY_STRING_NAME) {
str->cachedHash = hashCString(str->as.name.data);
}
return str->cachedHash;
}
case TOY_VALUE_ARRAY:
case TOY_VALUE_DICTIONARY:
case TOY_VALUE_FUNCTION:

View File

@@ -2,6 +2,9 @@
#include "toy_common.h"
//forward declarations
struct Toy_String;
typedef enum Toy_ValueType {
TOY_VALUE_NULL,
TOY_VALUE_BOOLEAN,
@@ -20,15 +23,15 @@ typedef struct Toy_Value { //32 | 64 BITNESS
bool boolean; //1 | 1
int integer; //4 | 4
float number; //4 | 4
//TODO: strings
struct Toy_String* string; //4 | 8
//TODO: arrays
//TODO: dictonaries
//TODO: functions
//TODO: opaque
} as; //4 | 4
} as; //4 | 8
Toy_ValueType type; //4 | 4
} Toy_Value; //8 | 8
} Toy_Value; //8 | 12
#define TOY_VALUE_IS_NULL(value) ((value).type == TOY_VALUE_NULL)
#define TOY_VALUE_IS_BOOLEAN(value) ((value).type == TOY_VALUE_BOOLEAN)
@@ -43,18 +46,21 @@ typedef struct Toy_Value { //32 | 64 BITNESS
#define TOY_VALUE_AS_BOOLEAN(value) ((value).as.boolean)
#define TOY_VALUE_AS_INTEGER(value) ((value).as.integer)
#define TOY_VALUE_AS_FLOAT(value) ((value).as.number)
#define TOY_VALUE_AS_STRING(value) ((value).as.string)
//TODO: more
#define TOY_VALUE_TO_NULL() ((Toy_Value){{ .integer = 0 }, TOY_VALUE_NULL})
#define TOY_VALUE_TO_BOOLEAN(value) ((Toy_Value){{ .boolean = value }, TOY_VALUE_BOOLEAN})
#define TOY_VALUE_TO_INTEGER(value) ((Toy_Value){{ .integer = value }, TOY_VALUE_INTEGER})
#define TOY_VALUE_TO_FLOAT(value) ((Toy_Value){{ .number = value }, TOY_VALUE_FLOAT})
#define TOY_VALUE_FROM_NULL() ((Toy_Value){{ .integer = 0 }, TOY_VALUE_NULL})
#define TOY_VALUE_FROM_BOOLEAN(value) ((Toy_Value){{ .boolean = value }, TOY_VALUE_BOOLEAN})
#define TOY_VALUE_FROM_INTEGER(value) ((Toy_Value){{ .integer = value }, TOY_VALUE_INTEGER})
#define TOY_VALUE_FROM_FLOAT(value) ((Toy_Value){{ .number = value }, TOY_VALUE_FLOAT})
#define TOY_VALUE_FROM_STRING(value) ((Toy_Value){{ .string = value }, TOY_VALUE_STRING})
//TODO: more
#define TOY_VALUE_IS_TRUTHY(value) Toy_private_isTruthy(value)
TOY_API bool Toy_private_isTruthy(Toy_Value value);
#define TOY_VALUE_IS_EQUAL(left, right) Toy_private_isEqual(left, right)
#define TOY_VALUES_ARE_EQUAL(left, right) Toy_private_isEqual(left, right)
TOY_API bool Toy_private_isEqual(Toy_Value left, Toy_Value right);
unsigned int Toy_hashValue(Toy_Value value);

View File

@@ -38,7 +38,7 @@ static inline void fix_alignment(Toy_VM* vm) {
static void processRead(Toy_VM* vm) {
Toy_ValueType type = READ_BYTE(vm);
Toy_Value value = TOY_VALUE_TO_NULL();
Toy_Value value = TOY_VALUE_FROM_NULL();
switch(type) {
case TOY_VALUE_NULL: {
@@ -47,19 +47,19 @@ static void processRead(Toy_VM* vm) {
}
case TOY_VALUE_BOOLEAN: {
value = TOY_VALUE_TO_BOOLEAN((bool)READ_BYTE(vm));
value = TOY_VALUE_FROM_BOOLEAN((bool)READ_BYTE(vm));
break;
}
case TOY_VALUE_INTEGER: {
fix_alignment(vm);
value = TOY_VALUE_TO_INTEGER(READ_INT(vm));
value = TOY_VALUE_FROM_INTEGER(READ_INT(vm));
break;
}
case TOY_VALUE_FLOAT: {
fix_alignment(vm);
value = TOY_VALUE_TO_FLOAT(READ_FLOAT(vm));
value = TOY_VALUE_FROM_FLOAT(READ_FLOAT(vm));
break;
}
@@ -126,30 +126,30 @@ static void processArithmetic(Toy_VM* vm, Toy_OpcodeType opcode) {
//coerce ints into floats if needed
if (TOY_VALUE_IS_INTEGER(left) && TOY_VALUE_IS_FLOAT(right)) {
left = TOY_VALUE_TO_FLOAT( (float)TOY_VALUE_AS_INTEGER(left) );
left = TOY_VALUE_FROM_FLOAT( (float)TOY_VALUE_AS_INTEGER(left) );
}
else
if (TOY_VALUE_IS_FLOAT(left) && TOY_VALUE_IS_INTEGER(right)) {
right = TOY_VALUE_TO_FLOAT( (float)TOY_VALUE_AS_INTEGER(right) );
right = TOY_VALUE_FROM_FLOAT( (float)TOY_VALUE_AS_INTEGER(right) );
}
//apply operation
Toy_Value result = TOY_VALUE_TO_NULL();
Toy_Value result = TOY_VALUE_FROM_NULL();
if (opcode == TOY_OPCODE_ADD) {
result = TOY_VALUE_IS_FLOAT(left) ? TOY_VALUE_TO_FLOAT( TOY_VALUE_AS_FLOAT(left) + TOY_VALUE_AS_FLOAT(right)) : TOY_VALUE_TO_INTEGER( TOY_VALUE_AS_INTEGER(left) + TOY_VALUE_AS_INTEGER(right) );
result = TOY_VALUE_IS_FLOAT(left) ? TOY_VALUE_FROM_FLOAT( TOY_VALUE_AS_FLOAT(left) + TOY_VALUE_AS_FLOAT(right)) : TOY_VALUE_FROM_INTEGER( TOY_VALUE_AS_INTEGER(left) + TOY_VALUE_AS_INTEGER(right) );
}
else if (opcode == TOY_OPCODE_SUBTRACT) {
result = TOY_VALUE_IS_FLOAT(left) ? TOY_VALUE_TO_FLOAT( TOY_VALUE_AS_FLOAT(left) - TOY_VALUE_AS_FLOAT(right)) : TOY_VALUE_TO_INTEGER( TOY_VALUE_AS_INTEGER(left) - TOY_VALUE_AS_INTEGER(right) );
result = TOY_VALUE_IS_FLOAT(left) ? TOY_VALUE_FROM_FLOAT( TOY_VALUE_AS_FLOAT(left) - TOY_VALUE_AS_FLOAT(right)) : TOY_VALUE_FROM_INTEGER( TOY_VALUE_AS_INTEGER(left) - TOY_VALUE_AS_INTEGER(right) );
}
else if (opcode == TOY_OPCODE_MULTIPLY) {
result = TOY_VALUE_IS_FLOAT(left) ? TOY_VALUE_TO_FLOAT( TOY_VALUE_AS_FLOAT(left) * TOY_VALUE_AS_FLOAT(right)) : TOY_VALUE_TO_INTEGER( TOY_VALUE_AS_INTEGER(left) * TOY_VALUE_AS_INTEGER(right) );
result = TOY_VALUE_IS_FLOAT(left) ? TOY_VALUE_FROM_FLOAT( TOY_VALUE_AS_FLOAT(left) * TOY_VALUE_AS_FLOAT(right)) : TOY_VALUE_FROM_INTEGER( TOY_VALUE_AS_INTEGER(left) * TOY_VALUE_AS_INTEGER(right) );
}
else if (opcode == TOY_OPCODE_DIVIDE) {
result = TOY_VALUE_IS_FLOAT(left) ? TOY_VALUE_TO_FLOAT( TOY_VALUE_AS_FLOAT(left) / TOY_VALUE_AS_FLOAT(right)) : TOY_VALUE_TO_INTEGER( TOY_VALUE_AS_INTEGER(left) / TOY_VALUE_AS_INTEGER(right) );
result = TOY_VALUE_IS_FLOAT(left) ? TOY_VALUE_FROM_FLOAT( TOY_VALUE_AS_FLOAT(left) / TOY_VALUE_AS_FLOAT(right)) : TOY_VALUE_FROM_INTEGER( TOY_VALUE_AS_INTEGER(left) / TOY_VALUE_AS_INTEGER(right) );
}
else if (opcode == TOY_OPCODE_MODULO) {
result = TOY_VALUE_TO_INTEGER( TOY_VALUE_AS_INTEGER(left) % TOY_VALUE_AS_INTEGER(right) );
result = TOY_VALUE_FROM_INTEGER( TOY_VALUE_AS_INTEGER(left) % TOY_VALUE_AS_INTEGER(right) );
}
else {
fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid opcode %d passed to processArithmetic, exiting\n" TOY_CC_RESET, opcode);
@@ -166,14 +166,14 @@ static void processComparison(Toy_VM* vm, Toy_OpcodeType opcode) {
//most things can be equal, so handle it separately
if (opcode == TOY_OPCODE_COMPARE_EQUAL) {
bool equal = TOY_VALUE_IS_EQUAL(left, right);
bool equal = TOY_VALUES_ARE_EQUAL(left, right);
//equality has an optional "negate" opcode within it's word
if (READ_BYTE(vm) != TOY_OPCODE_NEGATE) {
Toy_pushStack(&vm->stack, TOY_VALUE_TO_BOOLEAN(equal) );
Toy_pushStack(&vm->stack, TOY_VALUE_FROM_BOOLEAN(equal) );
}
else {
Toy_pushStack(&vm->stack, TOY_VALUE_TO_BOOLEAN(!equal) );
Toy_pushStack(&vm->stack, TOY_VALUE_FROM_BOOLEAN(!equal) );
}
return;
@@ -181,25 +181,25 @@ static void processComparison(Toy_VM* vm, Toy_OpcodeType opcode) {
//coerce ints into floats if needed
if (TOY_VALUE_IS_INTEGER(left) && TOY_VALUE_IS_FLOAT(right)) {
left = TOY_VALUE_TO_FLOAT( (float)TOY_VALUE_AS_INTEGER(left) );
left = TOY_VALUE_FROM_FLOAT( (float)TOY_VALUE_AS_INTEGER(left) );
}
else
if (TOY_VALUE_IS_FLOAT(left) && TOY_VALUE_IS_INTEGER(right)) {
right = TOY_VALUE_TO_FLOAT( (float)TOY_VALUE_AS_INTEGER(right) );
right = TOY_VALUE_FROM_FLOAT( (float)TOY_VALUE_AS_INTEGER(right) );
}
//other opcodes
if (opcode == TOY_OPCODE_COMPARE_LESS) {
Toy_pushStack(&vm->stack, TOY_VALUE_TO_BOOLEAN(TOY_VALUE_IS_FLOAT(left) ? TOY_VALUE_AS_FLOAT(left) < TOY_VALUE_AS_FLOAT(right) : TOY_VALUE_AS_INTEGER(left) < TOY_VALUE_AS_INTEGER(right)) );
Toy_pushStack(&vm->stack, TOY_VALUE_FROM_BOOLEAN(TOY_VALUE_IS_FLOAT(left) ? TOY_VALUE_AS_FLOAT(left) < TOY_VALUE_AS_FLOAT(right) : TOY_VALUE_AS_INTEGER(left) < TOY_VALUE_AS_INTEGER(right)) );
}
else if (opcode == TOY_OPCODE_COMPARE_LESS_EQUAL) {
Toy_pushStack(&vm->stack, TOY_VALUE_TO_BOOLEAN(TOY_VALUE_IS_FLOAT(left) ? TOY_VALUE_AS_FLOAT(left) <= TOY_VALUE_AS_FLOAT(right) : TOY_VALUE_AS_INTEGER(left) <= TOY_VALUE_AS_INTEGER(right)) );
Toy_pushStack(&vm->stack, TOY_VALUE_FROM_BOOLEAN(TOY_VALUE_IS_FLOAT(left) ? TOY_VALUE_AS_FLOAT(left) <= TOY_VALUE_AS_FLOAT(right) : TOY_VALUE_AS_INTEGER(left) <= TOY_VALUE_AS_INTEGER(right)) );
}
else if (opcode == TOY_OPCODE_COMPARE_GREATER) {
Toy_pushStack(&vm->stack, TOY_VALUE_TO_BOOLEAN(TOY_VALUE_IS_FLOAT(left) ? TOY_VALUE_AS_FLOAT(left) > TOY_VALUE_AS_FLOAT(right) : TOY_VALUE_AS_INTEGER(left) > TOY_VALUE_AS_INTEGER(right)) );
Toy_pushStack(&vm->stack, TOY_VALUE_FROM_BOOLEAN(TOY_VALUE_IS_FLOAT(left) ? TOY_VALUE_AS_FLOAT(left) > TOY_VALUE_AS_FLOAT(right) : TOY_VALUE_AS_INTEGER(left) > TOY_VALUE_AS_INTEGER(right)) );
}
else if (opcode == TOY_OPCODE_COMPARE_GREATER_EQUAL) {
Toy_pushStack(&vm->stack, TOY_VALUE_TO_BOOLEAN(TOY_VALUE_IS_FLOAT(left) ? TOY_VALUE_AS_FLOAT(left) >= TOY_VALUE_AS_FLOAT(right) : TOY_VALUE_AS_INTEGER(left) >= TOY_VALUE_AS_INTEGER(right)) );
Toy_pushStack(&vm->stack, TOY_VALUE_FROM_BOOLEAN(TOY_VALUE_IS_FLOAT(left) ? TOY_VALUE_AS_FLOAT(left) >= TOY_VALUE_AS_FLOAT(right) : TOY_VALUE_AS_INTEGER(left) >= TOY_VALUE_AS_INTEGER(right)) );
}
else {
fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid opcode %d passed to processComparison, exiting\n" TOY_CC_RESET, opcode);
@@ -212,23 +212,23 @@ static void processLogical(Toy_VM* vm, Toy_OpcodeType opcode) {
Toy_Value right = Toy_popStack(&vm->stack);
Toy_Value left = Toy_popStack(&vm->stack);
Toy_pushStack(&vm->stack, TOY_VALUE_TO_BOOLEAN( TOY_VALUE_IS_TRUTHY(left) && TOY_VALUE_IS_TRUTHY(right) ));
Toy_pushStack(&vm->stack, TOY_VALUE_FROM_BOOLEAN( TOY_VALUE_IS_TRUTHY(left) && TOY_VALUE_IS_TRUTHY(right) ));
}
else if (opcode == TOY_OPCODE_OR) {
Toy_Value right = Toy_popStack(&vm->stack);
Toy_Value left = Toy_popStack(&vm->stack);
Toy_pushStack(&vm->stack, TOY_VALUE_TO_BOOLEAN( TOY_VALUE_IS_TRUTHY(left) || TOY_VALUE_IS_TRUTHY(right) ));
Toy_pushStack(&vm->stack, TOY_VALUE_FROM_BOOLEAN( TOY_VALUE_IS_TRUTHY(left) || TOY_VALUE_IS_TRUTHY(right) ));
}
else if (opcode == TOY_OPCODE_TRUTHY) {
Toy_Value top = Toy_popStack(&vm->stack);
Toy_pushStack(&vm->stack, TOY_VALUE_TO_BOOLEAN( TOY_VALUE_IS_TRUTHY(top) ));
Toy_pushStack(&vm->stack, TOY_VALUE_FROM_BOOLEAN( TOY_VALUE_IS_TRUTHY(top) ));
}
else if (opcode == TOY_OPCODE_NEGATE) {
Toy_Value top = Toy_popStack(&vm->stack);
Toy_pushStack(&vm->stack, TOY_VALUE_TO_BOOLEAN( !TOY_VALUE_IS_TRUTHY(top) ));
Toy_pushStack(&vm->stack, TOY_VALUE_FROM_BOOLEAN( !TOY_VALUE_IS_TRUTHY(top) ));
}
else {
fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid opcode %d passed to processLogical, exiting\n" TOY_CC_RESET, opcode);