mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 14:54:07 +10:00
Implemented and tested Toy_String, read more
Strings are needed for the handling of identifiers in the key/value variable storage, so I've got them working first. I used the rope pattern, which seems to be quite an interesting approach. I'll add comparison checks later. Adjusted how buckets are handled in all tests, could've been an issue down the line. Added the build instructions to README.md.
This commit is contained in:
10
README.md
10
README.md
@@ -26,7 +26,15 @@ This repository holds the reference implementation for Toy version 2.x, written
|
|||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
*Omitted for review.*
|
Supported platforms are: `linux-latest`, `windows-latest`, `macos-latest`, using [GitHub's standard runners](https://docs.github.com/en/actions/using-github-hosted-runners/using-github-hosted-runners/about-github-hosted-runners#standard-github-hosted-runners-for-public-repositories).
|
||||||
|
|
||||||
|
To build the library, run `make source`.
|
||||||
|
|
||||||
|
To build the library and repl, run `make repl`.
|
||||||
|
|
||||||
|
To build and run the test cases, run `make tests`.
|
||||||
|
|
||||||
|
To build and run the test cases under gdb, run `make tests-gdb`.
|
||||||
|
|
||||||
## Tools
|
## Tools
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ void Toy_initBucket(Toy_Bucket** bucketHandle, size_t capacity) {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
(*bucketHandle) = malloc(sizeof(Toy_Bucket));
|
(*bucketHandle) = malloc(sizeof(Toy_Bucket)); //TODO: rework the bucket, so there's only one malloc() call instead of two when partitioning
|
||||||
|
|
||||||
if ((*bucketHandle) == NULL) {
|
if ((*bucketHandle) == NULL) {
|
||||||
fprintf(stderr, TOY_CC_ERROR "[internal] ERROR: Failed to allocate space for a bucket\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "[internal] ERROR: Failed to allocate space for a bucket\n" TOY_CC_RESET);
|
||||||
@@ -48,6 +48,12 @@ void* Toy_partBucket(Toy_Bucket** bucketHandle, size_t space) {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//if you try to allocate too much space
|
||||||
|
if ((*bucketHandle)->capacity < space) {
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "[internal] ERROR: Failed to partition bucket memory, not enough capacity\n" TOY_CC_RESET);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
//if out of space in the current bucket
|
//if out of space in the current bucket
|
||||||
if ((*bucketHandle)->capacity < (*bucketHandle)->count + space) {
|
if ((*bucketHandle)->capacity < (*bucketHandle)->count + space) {
|
||||||
//move to the next bucket
|
//move to the next bucket
|
||||||
|
|||||||
126
source/toy_string.c
Normal file
126
source/toy_string.c
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
#include "toy_string.h"
|
||||||
|
#include "toy_console_colors.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
//utils
|
||||||
|
static void deepCopyUtil(char* dest, Toy_String* str) {
|
||||||
|
//sometimes, "clever" can be a bad thing...
|
||||||
|
if (str->type == TOY_STRING_NODE) {
|
||||||
|
deepCopyUtil(dest, str->as.node.left);
|
||||||
|
deepCopyUtil(dest + str->as.node.left->length, str->as.node.right);
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
memcpy(dest, str->as.leaf.data, str->length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void incrementRefCount(Toy_String* str) {
|
||||||
|
str->refCount++;
|
||||||
|
if (str->type == TOY_STRING_NODE) {
|
||||||
|
incrementRefCount(str->as.node.left);
|
||||||
|
incrementRefCount(str->as.node.right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void decrementRefCount(Toy_String* str) {
|
||||||
|
str->refCount--;
|
||||||
|
if (str->type == TOY_STRING_NODE) {
|
||||||
|
decrementRefCount(str->as.node.left);
|
||||||
|
decrementRefCount(str->as.node.right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//exposed functions
|
||||||
|
Toy_String* Toy_createString(Toy_Bucket** bucket, const char* cstring) {
|
||||||
|
int length = strlen(cstring);
|
||||||
|
|
||||||
|
return Toy_createStringLength(bucket, cstring, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
Toy_String* Toy_createStringLength(Toy_Bucket** bucket, const char* cstring, int length) {
|
||||||
|
Toy_String* ret = (Toy_String*)Toy_partBucket(bucket, sizeof(Toy_String) + length + 1); //TODO: compensate for partitioning more space than bucket capacity
|
||||||
|
|
||||||
|
ret->type = TOY_STRING_LEAF;
|
||||||
|
ret->length = length;
|
||||||
|
ret->refCount = 1;
|
||||||
|
memcpy(ret->as.leaf.data, cstring, length);
|
||||||
|
ret->as.leaf.data[length] = '\0';
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Toy_String* Toy_copyString(Toy_Bucket** bucket, Toy_String* str) {
|
||||||
|
if (str->refCount <= 0) {
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Can't copy a string with refcount below or equal to zero\n" TOY_CC_RESET);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
incrementRefCount(str);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
Toy_String* Toy_deepCopyString(Toy_Bucket** bucket, Toy_String* str) {
|
||||||
|
if (str->refCount <= 0) {
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Can't deep copy a string with refcount below or equal to zero\n" TOY_CC_RESET);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
Toy_String* ret = (Toy_String*)Toy_partBucket(bucket, sizeof(Toy_String) + str->length + 1); //TODO: compensate for partitioning more space than bucket capacity
|
||||||
|
|
||||||
|
//TODO
|
||||||
|
ret->type = TOY_STRING_LEAF;
|
||||||
|
ret->length = str->length;
|
||||||
|
ret->refCount = 1;
|
||||||
|
deepCopyUtil(ret->as.leaf.data, str); //copy each leaf into the buffer
|
||||||
|
ret->as.leaf.data[ret->length] = '\0';
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Toy_String* Toy_concatString(Toy_Bucket** bucket, Toy_String* left, Toy_String* right) {
|
||||||
|
if (left->refCount <= 0 || right->refCount <= 0) {
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Can't concatenate a string with refcount below or equal to zero\n" TOY_CC_RESET);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Toy_String* ret = (Toy_String*)Toy_partBucket(bucket, sizeof(Toy_String));
|
||||||
|
|
||||||
|
ret->type = TOY_STRING_NODE;
|
||||||
|
ret->length = left->length + right->length;
|
||||||
|
ret->refCount = 1;
|
||||||
|
ret->as.node.left = left;
|
||||||
|
ret->as.node.right = right;
|
||||||
|
|
||||||
|
incrementRefCount(left);
|
||||||
|
incrementRefCount(right);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Toy_freeString(Toy_String* str) {
|
||||||
|
decrementRefCount(str); //TODO: tool for checking the bucket is empty, and freeing it
|
||||||
|
}
|
||||||
|
|
||||||
|
int Toy_getStringLength(Toy_String* str) {
|
||||||
|
return str->length;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Toy_getStringRefCount(Toy_String* str) {
|
||||||
|
return str->refCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* Toy_getStringRawBuffer(Toy_String* str) {
|
||||||
|
if (str->refCount <= 0) {
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Can't get raw string buffer of a string with refcount below or equal to zero\n" TOY_CC_RESET);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* buffer = TOY_ALLOCATE(char, str->length + 1);
|
||||||
|
|
||||||
|
deepCopyUtil(buffer, str);
|
||||||
|
buffer[str->length] = '\0';
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
43
source/toy_string.h
Normal file
43
source/toy_string.h
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
#include "toy_common.h"
|
||||||
|
|
||||||
|
#include "toy_memory.h"
|
||||||
|
|
||||||
|
//rope pattern
|
||||||
|
typedef struct Toy_String { //32 | 64 BITNESS
|
||||||
|
enum Toy_StringType {
|
||||||
|
TOY_STRING_NODE,
|
||||||
|
TOY_STRING_LEAF,
|
||||||
|
} type; //4 | 4
|
||||||
|
|
||||||
|
int length; //4 | 4
|
||||||
|
int refCount; //4 | 4
|
||||||
|
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
struct Toy_String* left; //4 | 8
|
||||||
|
struct Toy_String* right; //4 | 8
|
||||||
|
} node; //8 | 16
|
||||||
|
|
||||||
|
struct {
|
||||||
|
int dummy; //4 | 4
|
||||||
|
char data[]; //- | -
|
||||||
|
} leaf; //4 | 4
|
||||||
|
} as; //8 | 16
|
||||||
|
} Toy_String; //20 | 28
|
||||||
|
|
||||||
|
TOY_API Toy_String* Toy_createString(Toy_Bucket** bucket, const char* cstring);
|
||||||
|
TOY_API Toy_String* Toy_createStringLength(Toy_Bucket** bucket, const char* cstring, int length);
|
||||||
|
|
||||||
|
TOY_API Toy_String* Toy_copyString(Toy_Bucket** bucket, Toy_String* str);
|
||||||
|
TOY_API Toy_String* Toy_deepCopyString(Toy_Bucket** bucket, Toy_String* str);
|
||||||
|
|
||||||
|
TOY_API Toy_String* Toy_concatString(Toy_Bucket** bucket, Toy_String* left, Toy_String* right);
|
||||||
|
|
||||||
|
TOY_API void Toy_freeString(Toy_String* str);
|
||||||
|
|
||||||
|
TOY_API int Toy_getStringLength(Toy_String* str);
|
||||||
|
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
|
||||||
|
|
||||||
|
//TODO: compare
|
||||||
@@ -26,7 +26,8 @@ typedef struct Toy_VM {
|
|||||||
|
|
||||||
int routineCounter;
|
int routineCounter;
|
||||||
|
|
||||||
//scope - block-level key/value pairs
|
//heap - block-level key/value pairs
|
||||||
|
//TODO: needs string util for identifiers
|
||||||
|
|
||||||
//stack - immediate-level values only
|
//stack - immediate-level values only
|
||||||
Toy_Stack stack;
|
Toy_Stack stack;
|
||||||
|
|||||||
@@ -57,12 +57,12 @@ int test_sizeof_ast_32bit() {
|
|||||||
return -err;
|
return -err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int test_type_emission(Toy_Bucket* bucket) {
|
int test_type_emission(Toy_Bucket** bucket) {
|
||||||
//emit value
|
//emit value
|
||||||
{
|
{
|
||||||
//emit to an AST
|
//emit to an AST
|
||||||
Toy_Ast* ast = NULL;
|
Toy_Ast* ast = NULL;
|
||||||
Toy_private_emitAstValue(&bucket, &ast, TOY_VALUE_TO_INTEGER(42));
|
Toy_private_emitAstValue(bucket, &ast, TOY_VALUE_TO_INTEGER(42));
|
||||||
|
|
||||||
//check if it worked
|
//check if it worked
|
||||||
if (
|
if (
|
||||||
@@ -79,8 +79,8 @@ int test_type_emission(Toy_Bucket* bucket) {
|
|||||||
{
|
{
|
||||||
//build the AST
|
//build the AST
|
||||||
Toy_Ast* ast = NULL;
|
Toy_Ast* ast = NULL;
|
||||||
Toy_private_emitAstValue(&bucket, &ast, TOY_VALUE_TO_INTEGER(42));
|
Toy_private_emitAstValue(bucket, &ast, TOY_VALUE_TO_INTEGER(42));
|
||||||
Toy_private_emitAstUnary(&bucket, &ast, TOY_AST_FLAG_NEGATE);
|
Toy_private_emitAstUnary(bucket, &ast, TOY_AST_FLAG_NEGATE);
|
||||||
|
|
||||||
//check if it worked
|
//check if it worked
|
||||||
if (
|
if (
|
||||||
@@ -100,9 +100,9 @@ int test_type_emission(Toy_Bucket* bucket) {
|
|||||||
//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(&bucket, &ast, TOY_VALUE_TO_INTEGER(42));
|
Toy_private_emitAstValue(bucket, &ast, TOY_VALUE_TO_INTEGER(42));
|
||||||
Toy_private_emitAstValue(&bucket, &right, TOY_VALUE_TO_INTEGER(69));
|
Toy_private_emitAstValue(bucket, &right, TOY_VALUE_TO_INTEGER(69));
|
||||||
Toy_private_emitAstBinary(&bucket, &ast, TOY_AST_FLAG_ADD, right);
|
Toy_private_emitAstBinary(bucket, &ast, TOY_AST_FLAG_ADD, right);
|
||||||
|
|
||||||
//check if it worked
|
//check if it worked
|
||||||
if (
|
if (
|
||||||
@@ -124,10 +124,10 @@ int test_type_emission(Toy_Bucket* bucket) {
|
|||||||
//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(&bucket, &ast, TOY_VALUE_TO_INTEGER(42));
|
Toy_private_emitAstValue(bucket, &ast, TOY_VALUE_TO_INTEGER(42));
|
||||||
Toy_private_emitAstValue(&bucket, &right, TOY_VALUE_TO_INTEGER(69));
|
Toy_private_emitAstValue(bucket, &right, TOY_VALUE_TO_INTEGER(69));
|
||||||
Toy_private_emitAstBinary(&bucket, &ast, TOY_AST_FLAG_ADD, right);
|
Toy_private_emitAstBinary(bucket, &ast, TOY_AST_FLAG_ADD, right);
|
||||||
Toy_private_emitAstGroup(&bucket, &ast);
|
Toy_private_emitAstGroup(bucket, &ast);
|
||||||
|
|
||||||
//check if it worked
|
//check if it worked
|
||||||
if (
|
if (
|
||||||
@@ -150,19 +150,19 @@ int test_type_emission(Toy_Bucket* bucket) {
|
|||||||
{
|
{
|
||||||
//initialize the root block
|
//initialize the root block
|
||||||
Toy_Ast* block = NULL;
|
Toy_Ast* block = NULL;
|
||||||
Toy_private_initAstBlock(&bucket, &block);
|
Toy_private_initAstBlock(bucket, &block);
|
||||||
|
|
||||||
//loop over the ast emissions, appending each one as you go
|
//loop over the ast emissions, appending each one as you go
|
||||||
for (int i = 0; i < 5; i++) {
|
for (int i = 0; i < 5; i++) {
|
||||||
//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(&bucket, &ast, TOY_VALUE_TO_INTEGER(42));
|
Toy_private_emitAstValue(bucket, &ast, TOY_VALUE_TO_INTEGER(42));
|
||||||
Toy_private_emitAstValue(&bucket, &right, TOY_VALUE_TO_INTEGER(69));
|
Toy_private_emitAstValue(bucket, &right, TOY_VALUE_TO_INTEGER(69));
|
||||||
Toy_private_emitAstBinary(&bucket, &ast, TOY_AST_FLAG_ADD, right);
|
Toy_private_emitAstBinary(bucket, &ast, TOY_AST_FLAG_ADD, right);
|
||||||
Toy_private_emitAstGroup(&bucket, &ast);
|
Toy_private_emitAstGroup(bucket, &ast);
|
||||||
|
|
||||||
Toy_private_appendAstBlock(&bucket, &block, ast);
|
Toy_private_appendAstBlock(bucket, &block, ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
//check if it worked
|
//check if it worked
|
||||||
@@ -218,7 +218,7 @@ int main() {
|
|||||||
{
|
{
|
||||||
Toy_Bucket* bucket = NULL;
|
Toy_Bucket* bucket = NULL;
|
||||||
TOY_BUCKET_INIT(Toy_Ast, bucket, 32);
|
TOY_BUCKET_INIT(Toy_Ast, bucket, 32);
|
||||||
res = test_type_emission(bucket);
|
res = test_type_emission(&bucket);
|
||||||
TOY_BUCKET_FREE(bucket);
|
TOY_BUCKET_FREE(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);
|
||||||
|
|||||||
@@ -9,12 +9,12 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
//tests
|
//tests
|
||||||
int test_bytecode_header(Toy_Bucket* bucket) {
|
int test_bytecode_header(Toy_Bucket** bucket) {
|
||||||
//simple test to ensure the header looks right
|
//simple test to ensure the header looks right
|
||||||
{
|
{
|
||||||
//setup
|
//setup
|
||||||
Toy_Ast* ast = NULL;
|
Toy_Ast* ast = NULL;
|
||||||
Toy_private_emitAstPass(&bucket, &ast);
|
Toy_private_emitAstPass(bucket, &ast);
|
||||||
|
|
||||||
//run
|
//run
|
||||||
Toy_Bytecode bc = Toy_compileBytecode(ast);
|
Toy_Bytecode bc = Toy_compileBytecode(ast);
|
||||||
@@ -49,7 +49,7 @@ int test_bytecode_header(Toy_Bucket* bucket) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int test_bytecode_from_source(Toy_Bucket* bucket) {
|
int test_bytecode_from_source(Toy_Bucket** bucket) {
|
||||||
{
|
{
|
||||||
//setup
|
//setup
|
||||||
const char* source = "(1 + 2) * (3 + 4);";
|
const char* source = "(1 + 2) * (3 + 4);";
|
||||||
@@ -58,7 +58,7 @@ int test_bytecode_from_source(Toy_Bucket* bucket) {
|
|||||||
|
|
||||||
Toy_bindLexer(&lexer, source);
|
Toy_bindLexer(&lexer, source);
|
||||||
Toy_bindParser(&parser, &lexer);
|
Toy_bindParser(&parser, &lexer);
|
||||||
Toy_Ast* ast = Toy_scanParser(&bucket, &parser);
|
Toy_Ast* ast = Toy_scanParser(bucket, &parser);
|
||||||
|
|
||||||
//run
|
//run
|
||||||
Toy_Bytecode bc = Toy_compileBytecode(ast);
|
Toy_Bytecode bc = Toy_compileBytecode(ast);
|
||||||
@@ -177,7 +177,7 @@ int main() {
|
|||||||
{
|
{
|
||||||
Toy_Bucket* bucket = NULL;
|
Toy_Bucket* bucket = NULL;
|
||||||
TOY_BUCKET_INIT(Toy_Ast, bucket, 32);
|
TOY_BUCKET_INIT(Toy_Ast, bucket, 32);
|
||||||
res = test_bytecode_header(bucket);
|
res = test_bytecode_header(&bucket);
|
||||||
TOY_BUCKET_FREE(bucket);
|
TOY_BUCKET_FREE(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);
|
||||||
@@ -188,7 +188,7 @@ int main() {
|
|||||||
{
|
{
|
||||||
Toy_Bucket* bucket = NULL;
|
Toy_Bucket* bucket = NULL;
|
||||||
TOY_BUCKET_INIT(Toy_Ast, bucket, 32);
|
TOY_BUCKET_INIT(Toy_Ast, bucket, 32);
|
||||||
res = test_bytecode_from_source(bucket);
|
res = test_bytecode_from_source(&bucket);
|
||||||
TOY_BUCKET_FREE(bucket);
|
TOY_BUCKET_FREE(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);
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ Toy_Ast* makeAstFromSource(Toy_Bucket** bucket, const char* source) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//tests
|
//tests
|
||||||
int test_simple_empty_parsers(Toy_Bucket* bucket) {
|
int test_simple_empty_parsers(Toy_Bucket** bucket) {
|
||||||
//simple parser setup and cleanup
|
//simple parser setup and cleanup
|
||||||
{
|
{
|
||||||
//raw source code and lexer
|
//raw source code and lexer
|
||||||
@@ -27,7 +27,7 @@ int test_simple_empty_parsers(Toy_Bucket* bucket) {
|
|||||||
Toy_Parser parser;
|
Toy_Parser parser;
|
||||||
Toy_bindParser(&parser, &lexer);
|
Toy_bindParser(&parser, &lexer);
|
||||||
|
|
||||||
Toy_Ast* ast = Toy_scanParser(&bucket, &parser);
|
Toy_Ast* ast = Toy_scanParser(bucket, &parser);
|
||||||
|
|
||||||
//check if it worked
|
//check if it worked
|
||||||
if (
|
if (
|
||||||
@@ -50,7 +50,7 @@ int test_simple_empty_parsers(Toy_Bucket* bucket) {
|
|||||||
Toy_Parser parser;
|
Toy_Parser parser;
|
||||||
Toy_bindParser(&parser, &lexer);
|
Toy_bindParser(&parser, &lexer);
|
||||||
|
|
||||||
Toy_Ast* ast = Toy_scanParser(&bucket, &parser);
|
Toy_Ast* ast = Toy_scanParser(bucket, &parser);
|
||||||
|
|
||||||
//check if it worked
|
//check if it worked
|
||||||
if (
|
if (
|
||||||
@@ -75,7 +75,7 @@ int test_simple_empty_parsers(Toy_Bucket* bucket) {
|
|||||||
Toy_Parser parser;
|
Toy_Parser parser;
|
||||||
Toy_bindParser(&parser, &lexer);
|
Toy_bindParser(&parser, &lexer);
|
||||||
|
|
||||||
Toy_Ast* ast = Toy_scanParser(&bucket, &parser);
|
Toy_Ast* ast = Toy_scanParser(bucket, &parser);
|
||||||
|
|
||||||
Toy_Ast* iter = ast;
|
Toy_Ast* iter = ast;
|
||||||
|
|
||||||
@@ -98,10 +98,10 @@ int test_simple_empty_parsers(Toy_Bucket* bucket) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int test_values(Toy_Bucket* bucket) {
|
int test_values(Toy_Bucket** bucket) {
|
||||||
//test boolean true
|
//test boolean true
|
||||||
{
|
{
|
||||||
Toy_Ast* ast = makeAstFromSource(&bucket, "true;");
|
Toy_Ast* ast = makeAstFromSource(bucket, "true;");
|
||||||
|
|
||||||
//check if it worked
|
//check if it worked
|
||||||
if (
|
if (
|
||||||
@@ -119,7 +119,7 @@ int test_values(Toy_Bucket* bucket) {
|
|||||||
|
|
||||||
//test boolean false (just to be safe)
|
//test boolean false (just to be safe)
|
||||||
{
|
{
|
||||||
Toy_Ast* ast = makeAstFromSource(&bucket, "false;");
|
Toy_Ast* ast = makeAstFromSource(bucket, "false;");
|
||||||
|
|
||||||
//check if it worked
|
//check if it worked
|
||||||
if (
|
if (
|
||||||
@@ -137,7 +137,7 @@ int test_values(Toy_Bucket* bucket) {
|
|||||||
|
|
||||||
//test integer
|
//test integer
|
||||||
{
|
{
|
||||||
Toy_Ast* ast = makeAstFromSource(&bucket, "42;");
|
Toy_Ast* ast = makeAstFromSource(bucket, "42;");
|
||||||
|
|
||||||
//check if it worked
|
//check if it worked
|
||||||
if (
|
if (
|
||||||
@@ -155,7 +155,7 @@ int test_values(Toy_Bucket* bucket) {
|
|||||||
|
|
||||||
//test float
|
//test float
|
||||||
{
|
{
|
||||||
Toy_Ast* ast = makeAstFromSource(&bucket, "3.1415;");
|
Toy_Ast* ast = makeAstFromSource(bucket, "3.1415;");
|
||||||
|
|
||||||
//check if it worked
|
//check if it worked
|
||||||
if (
|
if (
|
||||||
@@ -173,7 +173,7 @@ int test_values(Toy_Bucket* bucket) {
|
|||||||
|
|
||||||
//test integer with separators
|
//test integer with separators
|
||||||
{
|
{
|
||||||
Toy_Ast* ast = makeAstFromSource(&bucket, "1_234_567_890;");
|
Toy_Ast* ast = makeAstFromSource(bucket, "1_234_567_890;");
|
||||||
|
|
||||||
//check if it worked
|
//check if it worked
|
||||||
if (
|
if (
|
||||||
@@ -191,7 +191,7 @@ int test_values(Toy_Bucket* bucket) {
|
|||||||
|
|
||||||
//test float with separators
|
//test float with separators
|
||||||
{
|
{
|
||||||
Toy_Ast* ast = makeAstFromSource(&bucket, "3.141_592_65;");
|
Toy_Ast* ast = makeAstFromSource(bucket, "3.141_592_65;");
|
||||||
|
|
||||||
//check if it worked
|
//check if it worked
|
||||||
if (
|
if (
|
||||||
@@ -210,10 +210,10 @@ int test_values(Toy_Bucket* bucket) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int test_unary(Toy_Bucket* bucket) {
|
int test_unary(Toy_Bucket** bucket) {
|
||||||
//test unary boolean negation (!true)
|
//test unary boolean negation (!true)
|
||||||
{
|
{
|
||||||
Toy_Ast* ast = makeAstFromSource(&bucket, "!true;");
|
Toy_Ast* ast = makeAstFromSource(bucket, "!true;");
|
||||||
|
|
||||||
//check if it worked
|
//check if it worked
|
||||||
if (
|
if (
|
||||||
@@ -231,7 +231,7 @@ int test_unary(Toy_Bucket* bucket) {
|
|||||||
|
|
||||||
//test unary boolean negation (!false, just to be safe)
|
//test unary boolean negation (!false, just to be safe)
|
||||||
{
|
{
|
||||||
Toy_Ast* ast = makeAstFromSource(&bucket, "!false;");
|
Toy_Ast* ast = makeAstFromSource(bucket, "!false;");
|
||||||
|
|
||||||
//check if it worked
|
//check if it worked
|
||||||
if (
|
if (
|
||||||
@@ -249,7 +249,7 @@ int test_unary(Toy_Bucket* bucket) {
|
|||||||
|
|
||||||
//test unary integer negation
|
//test unary integer negation
|
||||||
{
|
{
|
||||||
Toy_Ast* ast = makeAstFromSource(&bucket, "-42;");
|
Toy_Ast* ast = makeAstFromSource(bucket, "-42;");
|
||||||
|
|
||||||
//check if it worked
|
//check if it worked
|
||||||
if (
|
if (
|
||||||
@@ -267,7 +267,7 @@ int test_unary(Toy_Bucket* bucket) {
|
|||||||
|
|
||||||
//test unary float negation
|
//test unary float negation
|
||||||
{
|
{
|
||||||
Toy_Ast* ast = makeAstFromSource(&bucket, "-3.1415;");
|
Toy_Ast* ast = makeAstFromSource(bucket, "-3.1415;");
|
||||||
|
|
||||||
//check if it worked
|
//check if it worked
|
||||||
if (
|
if (
|
||||||
@@ -285,7 +285,7 @@ int test_unary(Toy_Bucket* bucket) {
|
|||||||
|
|
||||||
//ensure unary negation doesn't occur with a group
|
//ensure unary negation doesn't occur with a group
|
||||||
{
|
{
|
||||||
Toy_Ast* ast = makeAstFromSource(&bucket, "-(42);");
|
Toy_Ast* ast = makeAstFromSource(bucket, "-(42);");
|
||||||
|
|
||||||
//check if it worked
|
//check if it worked
|
||||||
if (
|
if (
|
||||||
@@ -301,7 +301,7 @@ int test_unary(Toy_Bucket* bucket) {
|
|||||||
|
|
||||||
//ensure unary negation doesn't occur with a space
|
//ensure unary negation doesn't occur with a space
|
||||||
{
|
{
|
||||||
Toy_Ast* ast = makeAstFromSource(&bucket, "- 42;");
|
Toy_Ast* ast = makeAstFromSource(bucket, "- 42;");
|
||||||
|
|
||||||
//check if it worked
|
//check if it worked
|
||||||
if (
|
if (
|
||||||
@@ -318,10 +318,10 @@ int test_unary(Toy_Bucket* bucket) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int test_binary(Toy_Bucket* bucket) {
|
int test_binary(Toy_Bucket** bucket) {
|
||||||
//test binary add (term); also covers subtract
|
//test binary add (term); also covers subtract
|
||||||
{
|
{
|
||||||
Toy_Ast* ast = makeAstFromSource(&bucket, "1 + 2;");
|
Toy_Ast* ast = makeAstFromSource(bucket, "1 + 2;");
|
||||||
|
|
||||||
//check if it worked
|
//check if it worked
|
||||||
if (
|
if (
|
||||||
@@ -348,7 +348,7 @@ int test_binary(Toy_Bucket* bucket) {
|
|||||||
|
|
||||||
//test binary multiply (factor); also covers divide and modulo
|
//test binary multiply (factor); also covers divide and modulo
|
||||||
{
|
{
|
||||||
Toy_Ast* ast = makeAstFromSource(&bucket, "3 * 5;");
|
Toy_Ast* ast = makeAstFromSource(bucket, "3 * 5;");
|
||||||
|
|
||||||
//check if it worked
|
//check if it worked
|
||||||
if (
|
if (
|
||||||
@@ -375,7 +375,7 @@ int test_binary(Toy_Bucket* bucket) {
|
|||||||
|
|
||||||
//test binary assign (using numbers for now, as identifiers aren't coded yet)
|
//test binary assign (using numbers for now, as identifiers aren't coded yet)
|
||||||
{
|
{
|
||||||
Toy_Ast* ast = makeAstFromSource(&bucket, "1 = 2;");
|
Toy_Ast* ast = makeAstFromSource(bucket, "1 = 2;");
|
||||||
|
|
||||||
//check if it worked
|
//check if it worked
|
||||||
if (
|
if (
|
||||||
@@ -402,7 +402,7 @@ int test_binary(Toy_Bucket* bucket) {
|
|||||||
|
|
||||||
//test binary compare (equality)
|
//test binary compare (equality)
|
||||||
{
|
{
|
||||||
Toy_Ast* ast = makeAstFromSource(&bucket, "42 == 69;");
|
Toy_Ast* ast = makeAstFromSource(bucket, "42 == 69;");
|
||||||
|
|
||||||
//check if it worked
|
//check if it worked
|
||||||
if (
|
if (
|
||||||
@@ -430,10 +430,10 @@ int test_binary(Toy_Bucket* bucket) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int test_precedence(Toy_Bucket* bucket) {
|
int test_precedence(Toy_Bucket** bucket) {
|
||||||
//test term-factor precedence
|
//test term-factor precedence
|
||||||
{
|
{
|
||||||
Toy_Ast* ast = makeAstFromSource(&bucket, "1 * 2 + 3 * 4;");
|
Toy_Ast* ast = makeAstFromSource(bucket, "1 * 2 + 3 * 4;");
|
||||||
|
|
||||||
//check if it worked
|
//check if it worked
|
||||||
if (
|
if (
|
||||||
@@ -474,7 +474,7 @@ int test_precedence(Toy_Bucket* bucket) {
|
|||||||
|
|
||||||
//test left-recrusive precedence
|
//test left-recrusive precedence
|
||||||
{
|
{
|
||||||
Toy_Ast* ast = makeAstFromSource(&bucket, "1 + 2 + 3 + 4 + 5 + 6;");
|
Toy_Ast* ast = makeAstFromSource(bucket, "1 + 2 + 3 + 4 + 5 + 6;");
|
||||||
|
|
||||||
//check if it worked
|
//check if it worked
|
||||||
if (
|
if (
|
||||||
@@ -531,7 +531,7 @@ int test_precedence(Toy_Bucket* bucket) {
|
|||||||
|
|
||||||
//test group precedence
|
//test group precedence
|
||||||
{
|
{
|
||||||
Toy_Ast* ast = makeAstFromSource(&bucket, "(1 + 2) * (3 + 4);");
|
Toy_Ast* ast = makeAstFromSource(bucket, "(1 + 2) * (3 + 4);");
|
||||||
|
|
||||||
//check if it worked
|
//check if it worked
|
||||||
if (
|
if (
|
||||||
@@ -580,7 +580,7 @@ int main() {
|
|||||||
{
|
{
|
||||||
Toy_Bucket* bucket = NULL;
|
Toy_Bucket* bucket = NULL;
|
||||||
TOY_BUCKET_INIT(Toy_Ast, bucket, 32);
|
TOY_BUCKET_INIT(Toy_Ast, bucket, 32);
|
||||||
res = test_simple_empty_parsers(bucket);
|
res = test_simple_empty_parsers(&bucket);
|
||||||
TOY_BUCKET_FREE(bucket);
|
TOY_BUCKET_FREE(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);
|
||||||
@@ -591,7 +591,7 @@ int main() {
|
|||||||
{
|
{
|
||||||
Toy_Bucket* bucket = NULL;
|
Toy_Bucket* bucket = NULL;
|
||||||
TOY_BUCKET_INIT(Toy_Ast, bucket, 32);
|
TOY_BUCKET_INIT(Toy_Ast, bucket, 32);
|
||||||
res = test_values(bucket);
|
res = test_values(&bucket);
|
||||||
TOY_BUCKET_FREE(bucket);
|
TOY_BUCKET_FREE(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);
|
||||||
@@ -602,7 +602,7 @@ int main() {
|
|||||||
{
|
{
|
||||||
Toy_Bucket* bucket = NULL;
|
Toy_Bucket* bucket = NULL;
|
||||||
TOY_BUCKET_INIT(Toy_Ast, bucket, 32);
|
TOY_BUCKET_INIT(Toy_Ast, bucket, 32);
|
||||||
res = test_unary(bucket);
|
res = test_unary(&bucket);
|
||||||
TOY_BUCKET_FREE(bucket);
|
TOY_BUCKET_FREE(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);
|
||||||
@@ -613,7 +613,7 @@ int main() {
|
|||||||
{
|
{
|
||||||
Toy_Bucket* bucket = NULL;
|
Toy_Bucket* bucket = NULL;
|
||||||
TOY_BUCKET_INIT(Toy_Ast, bucket, 32);
|
TOY_BUCKET_INIT(Toy_Ast, bucket, 32);
|
||||||
res = test_binary(bucket);
|
res = test_binary(&bucket);
|
||||||
TOY_BUCKET_FREE(bucket);
|
TOY_BUCKET_FREE(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);
|
||||||
@@ -624,7 +624,7 @@ int main() {
|
|||||||
{
|
{
|
||||||
Toy_Bucket* bucket = NULL;
|
Toy_Bucket* bucket = NULL;
|
||||||
TOY_BUCKET_INIT(Toy_Ast, bucket, 32);
|
TOY_BUCKET_INIT(Toy_Ast, bucket, 32);
|
||||||
res = test_precedence(bucket);
|
res = test_precedence(&bucket);
|
||||||
TOY_BUCKET_FREE(bucket);
|
TOY_BUCKET_FREE(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);
|
||||||
|
|||||||
@@ -9,12 +9,12 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
//tests
|
//tests
|
||||||
int test_routine_header_and_values(Toy_Bucket* bucket) {
|
int test_routine_header_and_values(Toy_Bucket** bucket) {
|
||||||
//simple test to ensure the header looks right with an empty ast
|
//simple test to ensure the header looks right with an empty ast
|
||||||
{
|
{
|
||||||
//setup
|
//setup
|
||||||
Toy_Ast* ast = NULL;
|
Toy_Ast* ast = NULL;
|
||||||
Toy_private_emitAstPass(&bucket, &ast);
|
Toy_private_emitAstPass(bucket, &ast);
|
||||||
|
|
||||||
//run
|
//run
|
||||||
void* buffer = Toy_compileRoutine(ast);
|
void* buffer = Toy_compileRoutine(ast);
|
||||||
@@ -63,7 +63,7 @@ int test_routine_header_and_values(Toy_Bucket* bucket) {
|
|||||||
|
|
||||||
Toy_bindLexer(&lexer, source);
|
Toy_bindLexer(&lexer, source);
|
||||||
Toy_bindParser(&parser, &lexer);
|
Toy_bindParser(&parser, &lexer);
|
||||||
Toy_Ast* ast = Toy_scanParser(&bucket, &parser);
|
Toy_Ast* ast = Toy_scanParser(bucket, &parser);
|
||||||
|
|
||||||
//run
|
//run
|
||||||
void* buffer = Toy_compileRoutine(ast);
|
void* buffer = Toy_compileRoutine(ast);
|
||||||
@@ -112,7 +112,7 @@ int test_routine_header_and_values(Toy_Bucket* bucket) {
|
|||||||
|
|
||||||
Toy_bindLexer(&lexer, source);
|
Toy_bindLexer(&lexer, source);
|
||||||
Toy_bindParser(&parser, &lexer);
|
Toy_bindParser(&parser, &lexer);
|
||||||
Toy_Ast* ast = Toy_scanParser(&bucket, &parser);
|
Toy_Ast* ast = Toy_scanParser(bucket, &parser);
|
||||||
|
|
||||||
//run
|
//run
|
||||||
void* buffer = Toy_compileRoutine(ast);
|
void* buffer = Toy_compileRoutine(ast);
|
||||||
@@ -165,7 +165,7 @@ int test_routine_header_and_values(Toy_Bucket* bucket) {
|
|||||||
|
|
||||||
Toy_bindLexer(&lexer, source);
|
Toy_bindLexer(&lexer, source);
|
||||||
Toy_bindParser(&parser, &lexer);
|
Toy_bindParser(&parser, &lexer);
|
||||||
Toy_Ast* ast = Toy_scanParser(&bucket, &parser);
|
Toy_Ast* ast = Toy_scanParser(bucket, &parser);
|
||||||
|
|
||||||
//run
|
//run
|
||||||
void* buffer = Toy_compileRoutine(ast);
|
void* buffer = Toy_compileRoutine(ast);
|
||||||
@@ -218,7 +218,7 @@ int test_routine_header_and_values(Toy_Bucket* bucket) {
|
|||||||
|
|
||||||
Toy_bindLexer(&lexer, source);
|
Toy_bindLexer(&lexer, source);
|
||||||
Toy_bindParser(&parser, &lexer);
|
Toy_bindParser(&parser, &lexer);
|
||||||
Toy_Ast* ast = Toy_scanParser(&bucket, &parser);
|
Toy_Ast* ast = Toy_scanParser(bucket, &parser);
|
||||||
|
|
||||||
//run
|
//run
|
||||||
void* buffer = Toy_compileRoutine(ast);
|
void* buffer = Toy_compileRoutine(ast);
|
||||||
@@ -272,7 +272,7 @@ int test_routine_header_and_values(Toy_Bucket* bucket) {
|
|||||||
|
|
||||||
Toy_bindLexer(&lexer, source);
|
Toy_bindLexer(&lexer, source);
|
||||||
Toy_bindParser(&parser, &lexer);
|
Toy_bindParser(&parser, &lexer);
|
||||||
Toy_Ast* ast = Toy_scanParser(&bucket, &parser);
|
Toy_Ast* ast = Toy_scanParser(bucket, &parser);
|
||||||
|
|
||||||
//run
|
//run
|
||||||
void* buffer = Toy_compileRoutine(ast);
|
void* buffer = Toy_compileRoutine(ast);
|
||||||
@@ -320,11 +320,11 @@ int test_routine_header_and_values(Toy_Bucket* bucket) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// int test_routine_unary(Toy_Bucket* bucket) {
|
// int test_routine_unary(Toy_Bucket** bucket) {
|
||||||
// //TODO: Nothing produces a unary instruction yet
|
// //TODO: Nothing produces a unary instruction yet
|
||||||
// }
|
// }
|
||||||
|
|
||||||
int test_routine_binary(Toy_Bucket* bucket) {
|
int test_routine_binary(Toy_Bucket** bucket) {
|
||||||
//produce a simple algorithm
|
//produce a simple algorithm
|
||||||
{
|
{
|
||||||
//setup
|
//setup
|
||||||
@@ -334,7 +334,7 @@ int test_routine_binary(Toy_Bucket* bucket) {
|
|||||||
|
|
||||||
Toy_bindLexer(&lexer, source);
|
Toy_bindLexer(&lexer, source);
|
||||||
Toy_bindParser(&parser, &lexer);
|
Toy_bindParser(&parser, &lexer);
|
||||||
Toy_Ast* ast = Toy_scanParser(&bucket, &parser);
|
Toy_Ast* ast = Toy_scanParser(bucket, &parser);
|
||||||
|
|
||||||
//run
|
//run
|
||||||
void* buffer = Toy_compileRoutine(ast);
|
void* buffer = Toy_compileRoutine(ast);
|
||||||
@@ -400,7 +400,7 @@ int test_routine_binary(Toy_Bucket* bucket) {
|
|||||||
|
|
||||||
Toy_bindLexer(&lexer, source);
|
Toy_bindLexer(&lexer, source);
|
||||||
Toy_bindParser(&parser, &lexer);
|
Toy_bindParser(&parser, &lexer);
|
||||||
Toy_Ast* ast = Toy_scanParser(&bucket, &parser);
|
Toy_Ast* ast = Toy_scanParser(bucket, &parser);
|
||||||
|
|
||||||
//run
|
//run
|
||||||
void* buffer = Toy_compileRoutine(ast);
|
void* buffer = Toy_compileRoutine(ast);
|
||||||
@@ -466,7 +466,7 @@ int test_routine_binary(Toy_Bucket* bucket) {
|
|||||||
|
|
||||||
Toy_bindLexer(&lexer, source);
|
Toy_bindLexer(&lexer, source);
|
||||||
Toy_bindParser(&parser, &lexer);
|
Toy_bindParser(&parser, &lexer);
|
||||||
Toy_Ast* ast = Toy_scanParser(&bucket, &parser);
|
Toy_Ast* ast = Toy_scanParser(bucket, &parser);
|
||||||
|
|
||||||
//run
|
//run
|
||||||
void* buffer = Toy_compileRoutine(ast);
|
void* buffer = Toy_compileRoutine(ast);
|
||||||
@@ -537,7 +537,7 @@ int test_routine_binary(Toy_Bucket* bucket) {
|
|||||||
|
|
||||||
Toy_bindLexer(&lexer, source);
|
Toy_bindLexer(&lexer, source);
|
||||||
Toy_bindParser(&parser, &lexer);
|
Toy_bindParser(&parser, &lexer);
|
||||||
Toy_Ast* ast = Toy_scanParser(&bucket, &parser);
|
Toy_Ast* ast = Toy_scanParser(bucket, &parser);
|
||||||
|
|
||||||
//run
|
//run
|
||||||
void* buffer = Toy_compileRoutine(ast);
|
void* buffer = Toy_compileRoutine(ast);
|
||||||
@@ -630,7 +630,7 @@ int main() {
|
|||||||
{
|
{
|
||||||
Toy_Bucket* bucket = NULL;
|
Toy_Bucket* bucket = NULL;
|
||||||
TOY_BUCKET_INIT(Toy_Ast, bucket, 32);
|
TOY_BUCKET_INIT(Toy_Ast, bucket, 32);
|
||||||
res = test_routine_header_and_values(bucket);
|
res = test_routine_header_and_values(&bucket);
|
||||||
TOY_BUCKET_FREE(bucket);
|
TOY_BUCKET_FREE(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);
|
||||||
@@ -641,7 +641,7 @@ int main() {
|
|||||||
{
|
{
|
||||||
Toy_Bucket* bucket = NULL;
|
Toy_Bucket* bucket = NULL;
|
||||||
TOY_BUCKET_INIT(Toy_Ast, bucket, 32);
|
TOY_BUCKET_INIT(Toy_Ast, bucket, 32);
|
||||||
res = test_routine_binary(bucket);
|
res = test_routine_binary(&bucket);
|
||||||
TOY_BUCKET_FREE(bucket);
|
TOY_BUCKET_FREE(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);
|
||||||
|
|||||||
316
tests/cases/test_string.c
Normal file
316
tests/cases/test_string.c
Normal file
@@ -0,0 +1,316 @@
|
|||||||
|
#include "toy_string.h"
|
||||||
|
#include "toy_console_colors.h"
|
||||||
|
|
||||||
|
#include "toy_memory.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
int test_sizeof_string_64bit() {
|
||||||
|
//test for the correct size
|
||||||
|
{
|
||||||
|
if (sizeof(Toy_String) != 28) {
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: 'Toy_String' is an unexpected size in memory\n" TOY_CC_RESET);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_sizeof_string_32bit() {
|
||||||
|
//test for the correct size
|
||||||
|
{
|
||||||
|
if (sizeof(Toy_String) != 20) {
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: 'Toy_String' is an unexpected size in memory\n" TOY_CC_RESET);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_string_allocation() {
|
||||||
|
//allocate a single string from a c-string
|
||||||
|
{
|
||||||
|
//setup
|
||||||
|
Toy_Bucket* bucket = NULL;
|
||||||
|
Toy_initBucket(&bucket, 32);
|
||||||
|
|
||||||
|
const char* cstring = "Hello world";
|
||||||
|
Toy_String* str = Toy_createString(&bucket, cstring);
|
||||||
|
|
||||||
|
//check
|
||||||
|
if (str->type != TOY_STRING_LEAF ||
|
||||||
|
str->length != 11 ||
|
||||||
|
str->refCount != 1 ||
|
||||||
|
strcmp(str->as.leaf.data, "Hello world") != 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to allocate a Toy_String with a private bucket\n" TOY_CC_RESET);
|
||||||
|
Toy_freeBucket(&bucket);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//free the string
|
||||||
|
Toy_freeString(str);
|
||||||
|
|
||||||
|
//inspect the bucket
|
||||||
|
if (bucket->capacity != 32 ||
|
||||||
|
bucket->count != sizeof(Toy_String) + 12 ||
|
||||||
|
bucket->next != NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Unexpected bucket state after a string was freed\n" TOY_CC_RESET);
|
||||||
|
Toy_freeBucket(&bucket);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//inspect the (now freed) string's memory
|
||||||
|
if (Toy_getStringRefCount(str) != 0) {
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Unexpected string state after it was freed\n" TOY_CC_RESET);
|
||||||
|
Toy_freeBucket(&bucket);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Toy_freeBucket(&bucket);
|
||||||
|
}
|
||||||
|
|
||||||
|
//copy and deep copy a string
|
||||||
|
{
|
||||||
|
//setup
|
||||||
|
Toy_Bucket* bucket = NULL;
|
||||||
|
Toy_initBucket(&bucket, 32);
|
||||||
|
|
||||||
|
const char* cstring = "Hello world";
|
||||||
|
Toy_String* str = Toy_createString(&bucket, cstring);
|
||||||
|
|
||||||
|
//shallow and deep
|
||||||
|
Toy_String* shallow = Toy_copyString(&bucket, str);
|
||||||
|
Toy_String* deep = Toy_deepCopyString(&bucket, str);
|
||||||
|
|
||||||
|
if (str != shallow ||
|
||||||
|
str == deep ||
|
||||||
|
shallow->refCount != 2 ||
|
||||||
|
deep->refCount != 1 ||
|
||||||
|
strcmp(shallow->as.leaf.data, deep->as.leaf.data) != 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to copy a string correctly\n" TOY_CC_RESET);
|
||||||
|
Toy_freeBucket(&bucket);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Toy_freeBucket(&bucket);
|
||||||
|
}
|
||||||
|
|
||||||
|
//allocate a zero-length string
|
||||||
|
{
|
||||||
|
//setup
|
||||||
|
Toy_Bucket* bucket = NULL;
|
||||||
|
Toy_initBucket(&bucket, 32);
|
||||||
|
|
||||||
|
const char* cstring = "";
|
||||||
|
Toy_String* str = Toy_createString(&bucket, cstring);
|
||||||
|
|
||||||
|
//check
|
||||||
|
if (str->type != TOY_STRING_LEAF ||
|
||||||
|
str->length != 0 ||
|
||||||
|
str->refCount != 1 ||
|
||||||
|
strcmp(str->as.leaf.data, "") != 0 ||
|
||||||
|
bucket->count != sizeof(Toy_String) + 1) //1 for the null character
|
||||||
|
{
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to allocate a Toy_String with zero length\n" TOY_CC_RESET);
|
||||||
|
Toy_freeBucket(&bucket);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//free the string
|
||||||
|
Toy_freeString(str);
|
||||||
|
|
||||||
|
Toy_freeBucket(&bucket);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_string_concatenation() {
|
||||||
|
//one big bucket o' fun
|
||||||
|
Toy_Bucket* bucket = NULL;
|
||||||
|
Toy_initBucket(&bucket, 1024);
|
||||||
|
|
||||||
|
//concatenate two strings, and check the refcounts
|
||||||
|
{
|
||||||
|
//setup
|
||||||
|
Toy_String* first = Toy_createString(&bucket, "Hello ");
|
||||||
|
Toy_String* second = Toy_createString(&bucket, "world");
|
||||||
|
|
||||||
|
//concatenate
|
||||||
|
Toy_String* result = Toy_concatString(&bucket, first, second);
|
||||||
|
|
||||||
|
//check the refcounts
|
||||||
|
if (first->refCount != 2 ||
|
||||||
|
second->refCount != 2 ||
|
||||||
|
result->refCount != 1 ||
|
||||||
|
result->length != 11)
|
||||||
|
{
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Unexpected state for string refcounts after concatenation\n" TOY_CC_RESET);
|
||||||
|
Toy_freeBucket(&bucket);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//clean up the separate strings
|
||||||
|
Toy_freeString(first);
|
||||||
|
Toy_freeString(second);
|
||||||
|
|
||||||
|
//check the refcounts again
|
||||||
|
if (first->refCount != 1 ||
|
||||||
|
second->refCount != 1 ||
|
||||||
|
result->refCount != 1 ||
|
||||||
|
result->length != 11)
|
||||||
|
{
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Unexpected state for string refcounts after concatenation and free\n" TOY_CC_RESET);
|
||||||
|
Toy_freeBucket(&bucket);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//clean up
|
||||||
|
Toy_freeString(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
//concatenate two strings, and check the resulting buffer
|
||||||
|
{
|
||||||
|
//setup
|
||||||
|
Toy_String* first = Toy_createString(&bucket, "Hello ");
|
||||||
|
Toy_String* second = Toy_createString(&bucket, "world");
|
||||||
|
|
||||||
|
//concatenate
|
||||||
|
Toy_String* result = Toy_concatString(&bucket, first, second);
|
||||||
|
|
||||||
|
char* buffer = Toy_getStringRawBuffer(result);
|
||||||
|
|
||||||
|
//check the refcounts
|
||||||
|
if (strlen(buffer) != 11 ||
|
||||||
|
strcmp(buffer, "Hello world") != 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to get the raw buffer from concatenated string\n" TOY_CC_RESET);
|
||||||
|
TOY_FREE_ARRAY(char, buffer, result->length + 1);
|
||||||
|
Toy_freeBucket(&bucket);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TOY_FREE_ARRAY(char, buffer, result->length + 1);
|
||||||
|
Toy_freeString(result);
|
||||||
|
Toy_freeString(first);
|
||||||
|
Toy_freeString(second);
|
||||||
|
}
|
||||||
|
|
||||||
|
Toy_freeBucket(&bucket);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_string_with_stressed_bucket() {
|
||||||
|
//how much is that dog in the window?
|
||||||
|
{
|
||||||
|
//test data: 36 characters total, 44 with spaces
|
||||||
|
char* testData[] = {
|
||||||
|
"the",
|
||||||
|
"quick",
|
||||||
|
"brown",
|
||||||
|
"fox",
|
||||||
|
"jumped", //longest word: 6 characters
|
||||||
|
"over",
|
||||||
|
"the",
|
||||||
|
"lazy",
|
||||||
|
"dog", //9 entries long
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
//setup
|
||||||
|
Toy_Bucket* bucket = NULL;
|
||||||
|
Toy_initBucket(&bucket, 128); //deliberately too short for one bucket
|
||||||
|
|
||||||
|
//stress
|
||||||
|
Toy_String* str = Toy_createString(&bucket, testData[0]);
|
||||||
|
Toy_String* ptr = str;
|
||||||
|
for (int i = 1; testData[i]; i++) {
|
||||||
|
str = Toy_concatString(&bucket, str, Toy_createString(&bucket, testData[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
//check
|
||||||
|
if (ptr->refCount != 9 ||
|
||||||
|
str->length != 36)
|
||||||
|
{
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Unexpected state of the string after stress test\n" TOY_CC_RESET);
|
||||||
|
Toy_freeBucket(&bucket);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//grab the buffer
|
||||||
|
char* buffer = Toy_getStringRawBuffer(str);
|
||||||
|
|
||||||
|
if (strcmp(buffer, "thequickbrownfoxjumpedoverthelazydog") != 0 ||
|
||||||
|
strlen(buffer) != 36)
|
||||||
|
{
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Unexpected state of the raw buffer after string stress test: '%s'\n" TOY_CC_RESET, buffer);
|
||||||
|
Toy_reallocate(buffer, 0, 0); //direct call to free, regardless of size
|
||||||
|
Toy_freeBucket(&bucket);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bucket->next == NULL) //just to make sure
|
||||||
|
{
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Unexpected state of the bucket after string stress test\n" TOY_CC_RESET);
|
||||||
|
Toy_reallocate(buffer, 0, 0); //direct call to free, regardless of size
|
||||||
|
Toy_freeBucket(&bucket);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//clean up
|
||||||
|
TOY_FREE_ARRAY(char, buffer, str->length);
|
||||||
|
Toy_freeBucket(&bucket);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
//run each test set, returning the total errors given
|
||||||
|
int total = 0, res = 0;
|
||||||
|
|
||||||
|
{
|
||||||
|
#if TOY_BITNESS == 64
|
||||||
|
res = test_sizeof_string_64bit();
|
||||||
|
#else
|
||||||
|
res = test_sizeof_string_32bit();
|
||||||
|
#endif
|
||||||
|
if (res == 0) {
|
||||||
|
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||||
|
}
|
||||||
|
total += res;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
res = test_string_allocation();
|
||||||
|
if (res == 0) {
|
||||||
|
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||||
|
}
|
||||||
|
total += res;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
res = test_string_concatenation();
|
||||||
|
if (res == 0) {
|
||||||
|
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||||
|
}
|
||||||
|
total += res;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
res = test_string_with_stressed_bucket();
|
||||||
|
if (res == 0) {
|
||||||
|
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||||
|
}
|
||||||
|
total += res;
|
||||||
|
}
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
@@ -23,7 +23,7 @@ Toy_Bytecode makeBytecodeFromSource(Toy_Bucket** bucket, const char* source) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//tests
|
//tests
|
||||||
int test_setup_and_teardown(Toy_Bucket* bucket) {
|
int test_setup_and_teardown(Toy_Bucket** bucket) {
|
||||||
//basic init & quit
|
//basic init & quit
|
||||||
{
|
{
|
||||||
//generate bytecode for testing
|
//generate bytecode for testing
|
||||||
@@ -35,7 +35,7 @@ int test_setup_and_teardown(Toy_Bucket* bucket) {
|
|||||||
Toy_Parser parser;
|
Toy_Parser parser;
|
||||||
Toy_bindParser(&parser, &lexer);
|
Toy_bindParser(&parser, &lexer);
|
||||||
|
|
||||||
Toy_Ast* ast = Toy_scanParser(&bucket, &parser);
|
Toy_Ast* ast = Toy_scanParser(bucket, &parser);
|
||||||
|
|
||||||
Toy_Bytecode bc = Toy_compileBytecode(ast);
|
Toy_Bytecode bc = Toy_compileBytecode(ast);
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ int test_setup_and_teardown(Toy_Bucket* bucket) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//tests
|
//tests
|
||||||
int test_simple_execution(Toy_Bucket* bucket) {
|
int test_simple_execution(Toy_Bucket** bucket) {
|
||||||
//basic init & quit
|
//basic init & quit
|
||||||
{
|
{
|
||||||
//generate bytecode for testing
|
//generate bytecode for testing
|
||||||
@@ -87,7 +87,7 @@ int test_simple_execution(Toy_Bucket* bucket) {
|
|||||||
Toy_Parser parser;
|
Toy_Parser parser;
|
||||||
Toy_bindParser(&parser, &lexer);
|
Toy_bindParser(&parser, &lexer);
|
||||||
|
|
||||||
Toy_Ast* ast = Toy_scanParser(&bucket, &parser);
|
Toy_Ast* ast = Toy_scanParser(bucket, &parser);
|
||||||
|
|
||||||
Toy_Bytecode bc = Toy_compileBytecode(ast);
|
Toy_Bytecode bc = Toy_compileBytecode(ast);
|
||||||
|
|
||||||
@@ -126,7 +126,7 @@ int main() {
|
|||||||
{
|
{
|
||||||
Toy_Bucket* bucket = NULL;
|
Toy_Bucket* bucket = NULL;
|
||||||
TOY_BUCKET_INIT(Toy_Ast, bucket, 32);
|
TOY_BUCKET_INIT(Toy_Ast, bucket, 32);
|
||||||
res = test_setup_and_teardown(bucket);
|
res = test_setup_and_teardown(&bucket);
|
||||||
TOY_BUCKET_FREE(bucket);
|
TOY_BUCKET_FREE(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);
|
||||||
@@ -137,7 +137,7 @@ int main() {
|
|||||||
{
|
{
|
||||||
Toy_Bucket* bucket = NULL;
|
Toy_Bucket* bucket = NULL;
|
||||||
TOY_BUCKET_INIT(Toy_Ast, bucket, 32);
|
TOY_BUCKET_INIT(Toy_Ast, bucket, 32);
|
||||||
res = test_simple_execution(bucket);
|
res = test_simple_execution(&bucket);
|
||||||
TOY_BUCKET_FREE(bucket);
|
TOY_BUCKET_FREE(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);
|
||||||
|
|||||||
Reference in New Issue
Block a user