mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 14:54:07 +10:00
Added CONTRIBUTING.md
Also renamed 'handles' throughout the project for consistency. Some meta files also had their file extensions added.
This commit is contained in:
@@ -1,3 +0,0 @@
|
|||||||
Add these to the docs somewhere:
|
|
||||||
|
|
||||||
double pointers are referred to as handles
|
|
||||||
129
CONTRIBUTING.md
Normal file
129
CONTRIBUTING.md
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
# Welcome to the Toy Programming Language
|
||||||
|
|
||||||
|
I'm extremely appreciative to have people contribute their time and expertise towards this project. Before I get into the details, let me give some high level goals:
|
||||||
|
|
||||||
|
* Toy is intended to work as an embedded scripting language inside a game engine, tentatively titled "Box".
|
||||||
|
* Toy's goal is to allow for a great degree of modability for any games developed with the Box engine.
|
||||||
|
* As such, using Toy itself should be easy for novice and veteran coders.
|
||||||
|
* Toy is developed with a focus on speed, efficient resource management, and portability.
|
||||||
|
* Toy should be a source of fun for everyone working on and using it.
|
||||||
|
|
||||||
|
# Where to Start
|
||||||
|
|
||||||
|
First, the main development branch of Toy is 'v2', with the branches 'v1' and 'v1-docs' kept for reference.
|
||||||
|
|
||||||
|
v2 is a ground-up rewrite, with additions, changes and deletions to the language that make sense. If you want to discuss the direction things are going, the [Discussions Tab](https://github.com/Ratstail91/Toy/discussions) is perfect for that.
|
||||||
|
|
||||||
|
The [Issue Tracker](https://github.com/Ratstail91/Toy/issues) is a good place to see what tasks and issues are currently waiting to be addressed. The [toy.h](https://github.com/Ratstail91/Toy/blob/v2/source/toy.h) source file is a quick way to see what building blocks are available in the source code. There are also a number of comments prepended with `TODO:` scattered throughout the source code, as reminders of planned features.
|
||||||
|
|
||||||
|
The [test cases](https://github.com/Ratstail91/Toy/tree/v2/tests/cases), which test individual parts of the code in isolation, can be a good way to see how those parts are used. Likewise, the [REPL](https://github.com/Ratstail91/Toy/tree/v2/repl) shows a practical usage of Toy.
|
||||||
|
|
||||||
|
*v2 is under heavy development, and as such may not be in a working state yet. Your patience and feedback can help, but missing features such as a documentation website are coming, eventually.*
|
||||||
|
|
||||||
|
# Building Blocks
|
||||||
|
|
||||||
|
These data structures should be as independent as they can be, but there are some dependencies:
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TB
|
||||||
|
Toy_Value ---> Toy_Stack
|
||||||
|
Toy_Array
|
||||||
|
Toy_Bucket ---> Toy_String
|
||||||
|
Toy_Value ---> Toy_Table
|
||||||
|
```
|
||||||
|
|
||||||
|
*TODO: Toy_Value will eventually depend on other structures, includeing those shown here, once the related features are implemented in v2.*
|
||||||
|
|
||||||
|
In addition, [toy_common.h](https://github.com/Ratstail91/Toy/blob/v2/source/toy_common.h) grants platform portability and version info, while [toy_console_colors.h](https://github.com/Ratstail91/Toy/blob/v2/source/toy_console_colors.h) provides string constants as macros that help with console output (where supported).
|
||||||
|
|
||||||
|
# Coding Habits
|
||||||
|
|
||||||
|
Here's a few coding habits that I use to keep the source code consistent. While I'd prefer contributors to follow these, breaking these guidelines are ok if you need to.
|
||||||
|
|
||||||
|
## Testing The Language
|
||||||
|
|
||||||
|
When adding a new piece of code, it must be thoroughly tested via a [test case](https://github.com/Ratstail91/Toy/tree/v2/tests/cases). If it has multiple features, they should be tested individually, and in combination with each other. Any kind of corner case which can cause an issue on any supported platform must be resolved (I'm happy to help with this, if needed).
|
||||||
|
|
||||||
|
This is probably the most important habit listed here. While I'm not too fussy as to how the tests are written, they do need to prove that the code works flawlessly. Toy is intended to be used by others (potentially many others), so please write simple and straight forward tests to ensure correctness.
|
||||||
|
|
||||||
|
## Tabs, 4 Characters Wide
|
||||||
|
|
||||||
|
I use tabs over spaces, with a width of 4. I don't have a linter, please don't make me use one.
|
||||||
|
|
||||||
|
## Error Messages
|
||||||
|
|
||||||
|
Fatal errors have this general format:
|
||||||
|
|
||||||
|
```c
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: [Info]\n" TOY_CC_RESET);
|
||||||
|
exit(-1);
|
||||||
|
```
|
||||||
|
|
||||||
|
The use of `fprintf()` will ensure the error is written to the console, and allows extra information to be printed - just replace `[Info]` with the relevant output. These kinds of fatal errors are intended to catch issues with the language itself, rather than errors in the Toy scripts.
|
||||||
|
|
||||||
|
In the test cases, the `exit(-1)` is instead replaced with `return -1` to allow `main()` to clean up that test set, and run others if needed.
|
||||||
|
|
||||||
|
## Naming Things
|
||||||
|
|
||||||
|
To ensure integrating Toy as an external library is easy, any functions that are intended for use should be:
|
||||||
|
|
||||||
|
* Marked with the macro `TOY_API`
|
||||||
|
* Prepended with `Toy_`
|
||||||
|
* Be named with lowerCamelCase
|
||||||
|
* Begin their name with a verb
|
||||||
|
|
||||||
|
Likewise, publicly visible structures should be:
|
||||||
|
|
||||||
|
* Prepended with `Toy_`
|
||||||
|
* Be named with UpperCamelCase
|
||||||
|
|
||||||
|
If you use a macro, ensure it is all uppercase, and prepended with `TOY_`. If there's a function that is exposed, but is intended to be used within a macro, prepending its name with `Toy_private_` is a good idea.
|
||||||
|
|
||||||
|
e.g.
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include "toy_common.h"
|
||||||
|
|
||||||
|
typedef struct Toy_Thing {
|
||||||
|
int member;
|
||||||
|
} Toy_Thing;
|
||||||
|
|
||||||
|
TOY_API void Toy_useThing();
|
||||||
|
|
||||||
|
#define TOY_USE_OTHER_THING() Toy_private_useOtherThing()
|
||||||
|
TOY_API void Toy_private_useOtherThing();
|
||||||
|
```
|
||||||
|
|
||||||
|
## Data Type Sizes
|
||||||
|
|
||||||
|
Within `toy_common.h`, the macro `TOY_BITNESS` is defined as either 32 or 64, depending on if Toy is compiled for 32 or 64 bit platforms (if it doesn't recognise a platform, it is set to -1).
|
||||||
|
|
||||||
|
Most, if not all the structures within Toy where memory layout is important have some comments indicating their sizes in memory based on bitness. These comments are only a guide, and should NOT be taken as gospel, but they're useful for thinking about how the data is laid out in memory. Spaces are used to line them up.
|
||||||
|
|
||||||
|
```c
|
||||||
|
//Copied from toy_stack.h
|
||||||
|
typedef struct Toy_Stack { //32 | 64 BITNESS
|
||||||
|
unsigned int capacity; //4 | 4
|
||||||
|
unsigned int count; //4 | 4
|
||||||
|
char data[]; //- | -
|
||||||
|
} Toy_Stack; //8 | 8
|
||||||
|
```
|
||||||
|
|
||||||
|
## Single and Double Pointers
|
||||||
|
|
||||||
|
Double pointers are used quite often, especially when a function performs some kind of operation on a structure itself, rather than just its data. I refer to these as "handles", and are usually named as such.
|
||||||
|
|
||||||
|
## Directories
|
||||||
|
|
||||||
|
The directories in the repository's root have certain intended uses. If you find a folder which is empty except for a file named `.gitkeep`, leave it be, as that file is simply used to retain that directory within git for later use.
|
||||||
|
|
||||||
|
| Directory | Intended Use |
|
||||||
|
| --- | --- |
|
||||||
|
| .github | Meta information used by GitHub, such as CI workflows and issue templates. |
|
||||||
|
| .notes | General storage for any kind of scratch notes or reminders, or random bits of source code that aren't needed. Rough ideas and plans are usually found here, but may be outdated. |
|
||||||
|
| lib | The source directory for various libraries external to Toy, but which can be made available by the host and accessed with the `import` keyword. |
|
||||||
|
| scripts | Storage for various example scripts written in Toy that can be loaded and executed by the repl. |
|
||||||
|
| source | The source directory for the core of the Toy programming language. |
|
||||||
|
| tests | The source directory for the testing systems. Within, `cases/` is used for test cases, `benchmarks/` for benchmarking, etc. |
|
||||||
|
| tools | The source directory for various external tools. |
|
||||||
|
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
Copyright (c) 2020-2024 Kayne Ruse, KR Game Studios
|
Copyright (c) 2020-2024 Kayne Ruse, KR Game Studios
|
||||||
|
|
||||||
This software is provided 'as-is', without any express or implied
|
This software is provided 'as-is', without any express or implied
|
||||||
warranty. In no event will the authors be held liable for any damages
|
warranty. In no event will the authors be held liable for any damages
|
||||||
arising from the use of this software.
|
arising from the use of this software.
|
||||||
|
|
||||||
Permission is granted to anyone to use this software for any purpose,
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
including commercial applications, and to alter it and redistribute it
|
including commercial applications, and to alter it and redistribute it
|
||||||
freely, subject to the following restrictions:
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
1. The origin of this software must not be misrepresented; you must not
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
claim that you wrote the original software. If you use this software
|
claim that you wrote the original software. If you use this software
|
||||||
in a product, an acknowledgment in the product documentation would be
|
in a product, an acknowledgment in the product documentation would be
|
||||||
appreciated but is not required.
|
appreciated but is not required.
|
||||||
2. Altered source versions must be plainly marked as such, and must not be
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
misrepresented as being the original software.
|
misrepresented as being the original software.
|
||||||
3. This notice may not be removed or altered from any source distribution.
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
@@ -39,10 +39,12 @@ To build and run the test cases under gdb, run `make tests-gdb`.
|
|||||||
|
|
||||||
# License
|
# License
|
||||||
|
|
||||||
This source code is covered by the zlib license (see [LICENSE](LICENSE)).
|
This source code is covered by the zlib license (see [LICENSE.md](LICENSE.md)).
|
||||||
|
|
||||||
# Contributors and Special Thanks
|
# Contributors and Special Thanks
|
||||||
|
|
||||||
|
For a guide on how you can contribute, see [CONTRIBUTING.md](CONTRIBUTING.md).
|
||||||
|
|
||||||
@hiperiondev - v1 Disassembler, v1 porting support and feedback
|
@hiperiondev - v1 Disassembler, v1 porting support and feedback
|
||||||
@add00 - v1 Library support
|
@add00 - v1 Library support
|
||||||
@gruelingpine185 - Unofficial v1 MacOS support
|
@gruelingpine185 - Unofficial v1 MacOS support
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
#include "toy_ast.h"
|
#include "toy_ast.h"
|
||||||
|
|
||||||
void Toy_private_initAstBlock(Toy_Bucket** bucket, Toy_Ast** handle) {
|
void Toy_private_initAstBlock(Toy_Bucket** bucketHandle, Toy_Ast** astHandle) {
|
||||||
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucket, sizeof(Toy_Ast));
|
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast));
|
||||||
|
|
||||||
tmp->type = TOY_AST_BLOCK;
|
tmp->type = TOY_AST_BLOCK;
|
||||||
tmp->block.child = NULL;
|
tmp->block.child = NULL;
|
||||||
tmp->block.next = NULL;
|
tmp->block.next = NULL;
|
||||||
tmp->block.tail = NULL;
|
tmp->block.tail = NULL;
|
||||||
|
|
||||||
(*handle) = tmp;
|
(*astHandle) = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Toy_private_appendAstBlock(Toy_Bucket** bucket, Toy_Ast* block, Toy_Ast* child) {
|
void Toy_private_appendAstBlock(Toy_Bucket** bucketHandle, Toy_Ast* block, Toy_Ast* child) {
|
||||||
//first, check if we're an empty head
|
//first, check if we're an empty head
|
||||||
if (block->block.child == NULL) {
|
if (block->block.child == NULL) {
|
||||||
block->block.child = child;
|
block->block.child = child;
|
||||||
@@ -26,72 +26,72 @@ void Toy_private_appendAstBlock(Toy_Bucket** bucket, Toy_Ast* block, Toy_Ast* ch
|
|||||||
}
|
}
|
||||||
|
|
||||||
//append a new link to the chain
|
//append a new link to the chain
|
||||||
Toy_private_initAstBlock(bucket, &(iter->block.next));
|
Toy_private_initAstBlock(bucketHandle, &(iter->block.next));
|
||||||
|
|
||||||
//store the child in the new link, prep the tail pointer
|
//store the child in the new link, prep the tail pointer
|
||||||
iter->block.next->block.child = child;
|
iter->block.next->block.child = child;
|
||||||
block->block.tail = iter->block.next;
|
block->block.tail = iter->block.next;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Toy_private_emitAstValue(Toy_Bucket** bucket, Toy_Ast** handle, Toy_Value value) {
|
void Toy_private_emitAstValue(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_Value value) {
|
||||||
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucket, sizeof(Toy_Ast));
|
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast));
|
||||||
|
|
||||||
tmp->type = TOY_AST_VALUE;
|
tmp->type = TOY_AST_VALUE;
|
||||||
tmp->value.value = value;
|
tmp->value.value = value;
|
||||||
|
|
||||||
(*handle) = tmp;
|
(*astHandle) = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Toy_private_emitAstUnary(Toy_Bucket** bucket, Toy_Ast** handle, Toy_AstFlag flag) {
|
void Toy_private_emitAstUnary(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_AstFlag flag) {
|
||||||
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucket, sizeof(Toy_Ast));
|
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast));
|
||||||
|
|
||||||
tmp->type = TOY_AST_UNARY;
|
tmp->type = TOY_AST_UNARY;
|
||||||
tmp->unary.flag = flag;
|
tmp->unary.flag = flag;
|
||||||
tmp->unary.child = *handle;
|
tmp->unary.child = *astHandle;
|
||||||
|
|
||||||
(*handle) = tmp;
|
(*astHandle) = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Toy_private_emitAstBinary(Toy_Bucket** bucket, Toy_Ast** handle, Toy_AstFlag flag, Toy_Ast* right) {
|
void Toy_private_emitAstBinary(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_AstFlag flag, Toy_Ast* right) {
|
||||||
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucket, sizeof(Toy_Ast));
|
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast));
|
||||||
|
|
||||||
tmp->type = TOY_AST_BINARY;
|
tmp->type = TOY_AST_BINARY;
|
||||||
tmp->binary.flag = flag;
|
tmp->binary.flag = flag;
|
||||||
tmp->binary.left = *handle; //left-recursive
|
tmp->binary.left = *astHandle; //left-recursive
|
||||||
tmp->binary.right = right;
|
tmp->binary.right = right;
|
||||||
|
|
||||||
(*handle) = tmp;
|
(*astHandle) = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Toy_private_emitAstGroup(Toy_Bucket** bucket, Toy_Ast** handle) {
|
void Toy_private_emitAstGroup(Toy_Bucket** bucketHandle, Toy_Ast** astHandle) {
|
||||||
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucket, sizeof(Toy_Ast));
|
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast));
|
||||||
|
|
||||||
tmp->type = TOY_AST_GROUP;
|
tmp->type = TOY_AST_GROUP;
|
||||||
tmp->group.child = (*handle);
|
tmp->group.child = (*astHandle);
|
||||||
|
|
||||||
(*handle) = tmp;
|
(*astHandle) = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Toy_private_emitAstPass(Toy_Bucket** bucket, Toy_Ast** handle) {
|
void Toy_private_emitAstPass(Toy_Bucket** bucketHandle, Toy_Ast** astHandle) {
|
||||||
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucket, sizeof(Toy_Ast));
|
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast));
|
||||||
|
|
||||||
tmp->type = TOY_AST_PASS;
|
tmp->type = TOY_AST_PASS;
|
||||||
|
|
||||||
(*handle) = tmp;
|
(*astHandle) = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Toy_private_emitAstError(Toy_Bucket** bucket, Toy_Ast** handle) {
|
void Toy_private_emitAstError(Toy_Bucket** bucketHandle, Toy_Ast** astHandle) {
|
||||||
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucket, sizeof(Toy_Ast));
|
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast));
|
||||||
|
|
||||||
tmp->type = TOY_AST_ERROR;
|
tmp->type = TOY_AST_ERROR;
|
||||||
|
|
||||||
(*handle) = tmp;
|
(*astHandle) = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Toy_private_emitAstEnd(Toy_Bucket** bucket, Toy_Ast** handle) {
|
void Toy_private_emitAstEnd(Toy_Bucket** bucketHandle, Toy_Ast** astHandle) {
|
||||||
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucket, sizeof(Toy_Ast));
|
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast));
|
||||||
|
|
||||||
tmp->type = TOY_AST_END;
|
tmp->type = TOY_AST_END;
|
||||||
|
|
||||||
(*handle) = tmp;
|
(*astHandle) = tmp;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -110,14 +110,14 @@ union Toy_Ast { //32 | 64 BITNESS
|
|||||||
Toy_AstEnd end; //4 | 4
|
Toy_AstEnd end; //4 | 4
|
||||||
}; //16 | 32
|
}; //16 | 32
|
||||||
|
|
||||||
void Toy_private_initAstBlock(Toy_Bucket** bucket, Toy_Ast** handle);
|
void Toy_private_initAstBlock(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);
|
||||||
void Toy_private_appendAstBlock(Toy_Bucket** bucket, Toy_Ast* block, Toy_Ast* child);
|
void Toy_private_appendAstBlock(Toy_Bucket** bucketHandle, Toy_Ast* block, Toy_Ast* child);
|
||||||
|
|
||||||
void Toy_private_emitAstValue(Toy_Bucket** bucket, Toy_Ast** handle, Toy_Value value);
|
void Toy_private_emitAstValue(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_Value value);
|
||||||
void Toy_private_emitAstUnary(Toy_Bucket** bucket, Toy_Ast** handle, Toy_AstFlag flag);
|
void Toy_private_emitAstUnary(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_AstFlag flag);
|
||||||
void Toy_private_emitAstBinary(Toy_Bucket** bucket, Toy_Ast** handle,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_emitAstGroup(Toy_Bucket** bucket, Toy_Ast** handle);
|
void Toy_private_emitAstGroup(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);
|
||||||
|
|
||||||
void Toy_private_emitAstPass(Toy_Bucket** bucket, Toy_Ast** handle);
|
void Toy_private_emitAstPass(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);
|
||||||
void Toy_private_emitAstError(Toy_Bucket** bucket, Toy_Ast** handle);
|
void Toy_private_emitAstError(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);
|
||||||
void Toy_private_emitAstEnd(Toy_Bucket** bucket, Toy_Ast** handle);
|
void Toy_private_emitAstEnd(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);
|
||||||
@@ -97,7 +97,7 @@ typedef enum ParsingPrecedence {
|
|||||||
PREC_PRIMARY,
|
PREC_PRIMARY,
|
||||||
} ParsingPrecedence;
|
} ParsingPrecedence;
|
||||||
|
|
||||||
typedef Toy_AstFlag (*ParsingRule)(Toy_Bucket** bucket, Toy_Parser* parser, Toy_Ast** root);
|
typedef Toy_AstFlag (*ParsingRule)(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle);
|
||||||
|
|
||||||
typedef struct ParsingTuple {
|
typedef struct ParsingTuple {
|
||||||
ParsingPrecedence precedence;
|
ParsingPrecedence precedence;
|
||||||
@@ -105,12 +105,12 @@ typedef struct ParsingTuple {
|
|||||||
ParsingRule infix;
|
ParsingRule infix;
|
||||||
} ParsingTuple;
|
} ParsingTuple;
|
||||||
|
|
||||||
static void parsePrecedence(Toy_Bucket** bucket, Toy_Parser* parser, Toy_Ast** root, ParsingPrecedence precRule);
|
static void parsePrecedence(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle, ParsingPrecedence precRule);
|
||||||
|
|
||||||
static Toy_AstFlag atomic(Toy_Bucket** bucket, Toy_Parser* parser, Toy_Ast** root);
|
static Toy_AstFlag atomic(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle);
|
||||||
static Toy_AstFlag unary(Toy_Bucket** bucket, Toy_Parser* parser, Toy_Ast** root);
|
static Toy_AstFlag unary(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle);
|
||||||
static Toy_AstFlag binary(Toy_Bucket** bucket, Toy_Parser* parser, Toy_Ast** root);
|
static Toy_AstFlag binary(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle);
|
||||||
static Toy_AstFlag group(Toy_Bucket** bucket, Toy_Parser* parser, Toy_Ast** root);
|
static Toy_AstFlag group(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle);
|
||||||
|
|
||||||
//precedence definitions
|
//precedence definitions
|
||||||
static ParsingTuple parsingRulesetTable[] = {
|
static ParsingTuple parsingRulesetTable[] = {
|
||||||
@@ -214,18 +214,18 @@ static ParsingTuple parsingRulesetTable[] = {
|
|||||||
{PREC_NONE,NULL,NULL},// TOY_TOKEN_EOF,
|
{PREC_NONE,NULL,NULL},// TOY_TOKEN_EOF,
|
||||||
};
|
};
|
||||||
|
|
||||||
static Toy_AstFlag atomic(Toy_Bucket** bucket, Toy_Parser* parser, Toy_Ast** root) {
|
static Toy_AstFlag atomic(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {
|
||||||
switch(parser->previous.type) {
|
switch(parser->previous.type) {
|
||||||
case TOY_TOKEN_NULL:
|
case TOY_TOKEN_NULL:
|
||||||
Toy_private_emitAstValue(bucket, root, TOY_VALUE_TO_NULL());
|
Toy_private_emitAstValue(bucketHandle, rootHandle, TOY_VALUE_TO_NULL());
|
||||||
return TOY_AST_FLAG_NONE;
|
return TOY_AST_FLAG_NONE;
|
||||||
|
|
||||||
case TOY_TOKEN_LITERAL_TRUE:
|
case TOY_TOKEN_LITERAL_TRUE:
|
||||||
Toy_private_emitAstValue(bucket, root, TOY_VALUE_TO_BOOLEAN(true));
|
Toy_private_emitAstValue(bucketHandle, rootHandle, TOY_VALUE_TO_BOOLEAN(true));
|
||||||
return TOY_AST_FLAG_NONE;
|
return TOY_AST_FLAG_NONE;
|
||||||
|
|
||||||
case TOY_TOKEN_LITERAL_FALSE:
|
case TOY_TOKEN_LITERAL_FALSE:
|
||||||
Toy_private_emitAstValue(bucket, root, TOY_VALUE_TO_BOOLEAN(false));
|
Toy_private_emitAstValue(bucketHandle, rootHandle, TOY_VALUE_TO_BOOLEAN(false));
|
||||||
return TOY_AST_FLAG_NONE;
|
return TOY_AST_FLAG_NONE;
|
||||||
|
|
||||||
case TOY_TOKEN_LITERAL_INTEGER: {
|
case TOY_TOKEN_LITERAL_INTEGER: {
|
||||||
@@ -241,7 +241,7 @@ static Toy_AstFlag atomic(Toy_Bucket** bucket, Toy_Parser* parser, Toy_Ast** roo
|
|||||||
|
|
||||||
int value = 0;
|
int value = 0;
|
||||||
sscanf(buffer, "%d", &value);
|
sscanf(buffer, "%d", &value);
|
||||||
Toy_private_emitAstValue(bucket, root, TOY_VALUE_TO_INTEGER(value));
|
Toy_private_emitAstValue(bucketHandle, rootHandle, TOY_VALUE_TO_INTEGER(value));
|
||||||
return TOY_AST_FLAG_NONE;
|
return TOY_AST_FLAG_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,173 +258,173 @@ static Toy_AstFlag atomic(Toy_Bucket** bucket, Toy_Parser* parser, Toy_Ast** roo
|
|||||||
|
|
||||||
float value = 0;
|
float value = 0;
|
||||||
sscanf(buffer, "%f", &value);
|
sscanf(buffer, "%f", &value);
|
||||||
Toy_private_emitAstValue(bucket, root, TOY_VALUE_TO_FLOAT(value));
|
Toy_private_emitAstValue(bucketHandle, rootHandle, TOY_VALUE_TO_FLOAT(value));
|
||||||
return TOY_AST_FLAG_NONE;
|
return TOY_AST_FLAG_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
printError(parser, parser->previous, "Unexpected token passed to atomic precedence rule");
|
printError(parser, parser->previous, "Unexpected token passed to atomic precedence rule");
|
||||||
Toy_private_emitAstError(bucket, root);
|
Toy_private_emitAstError(bucketHandle, rootHandle);
|
||||||
return TOY_AST_FLAG_NONE;
|
return TOY_AST_FLAG_NONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Toy_AstFlag unary(Toy_Bucket** bucket, Toy_Parser* parser, Toy_Ast** root) {
|
static Toy_AstFlag unary(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {
|
||||||
//'subtract' can only be applied to numbers and groups, while 'negate' can only be applied to booleans and groups
|
//'subtract' can only be applied to numbers and groups, while 'negate' can only be applied to booleans and groups
|
||||||
//this function takes the libery of peeking into the uppermost node, to see if it can apply this to it
|
//this function takes the libery of peeking into the uppermost node, to see if it can apply this to it
|
||||||
|
|
||||||
if (parser->previous.type == TOY_TOKEN_OPERATOR_SUBTRACT) {
|
if (parser->previous.type == TOY_TOKEN_OPERATOR_SUBTRACT) {
|
||||||
|
|
||||||
bool connectedDigit = parser->previous.lexeme[1] >= '0' && parser->previous.lexeme[1] <= '9'; //BUGFIX: '- 1' should not be optimised into a negative
|
bool connectedDigit = parser->previous.lexeme[1] >= '0' && parser->previous.lexeme[1] <= '9'; //BUGFIX: '- 1' should not be optimised into a negative
|
||||||
parsePrecedence(bucket, parser, root, PREC_UNARY);
|
parsePrecedence(bucketHandle, parser, rootHandle, PREC_UNARY);
|
||||||
|
|
||||||
//negative numbers
|
//negative numbers
|
||||||
if ((*root)->type == TOY_AST_VALUE && TOY_VALUE_IS_INTEGER((*root)->value.value) && connectedDigit) {
|
if ((*rootHandle)->type == TOY_AST_VALUE && TOY_VALUE_IS_INTEGER((*rootHandle)->value.value) && connectedDigit) {
|
||||||
(*root)->value.value = TOY_VALUE_TO_INTEGER( -TOY_VALUE_AS_INTEGER((*root)->value.value) );
|
(*rootHandle)->value.value = TOY_VALUE_TO_INTEGER( -TOY_VALUE_AS_INTEGER((*rootHandle)->value.value) );
|
||||||
}
|
}
|
||||||
else if ((*root)->type == TOY_AST_VALUE && TOY_VALUE_IS_FLOAT((*root)->value.value) && connectedDigit) {
|
else if ((*rootHandle)->type == TOY_AST_VALUE && TOY_VALUE_IS_FLOAT((*rootHandle)->value.value) && connectedDigit) {
|
||||||
(*root)->value.value = TOY_VALUE_TO_FLOAT( -TOY_VALUE_AS_FLOAT((*root)->value.value) );
|
(*rootHandle)->value.value = TOY_VALUE_TO_FLOAT( -TOY_VALUE_AS_FLOAT((*rootHandle)->value.value) );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
//actually emit the negation node
|
//actually emit the negation node
|
||||||
Toy_private_emitAstUnary(bucket, root, TOY_AST_FLAG_NEGATE);
|
Toy_private_emitAstUnary(bucketHandle, rootHandle, TOY_AST_FLAG_NEGATE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (parser->previous.type == TOY_TOKEN_OPERATOR_NEGATE) {
|
else if (parser->previous.type == TOY_TOKEN_OPERATOR_NEGATE) {
|
||||||
parsePrecedence(bucket, parser, root, PREC_UNARY);
|
parsePrecedence(bucketHandle, parser, rootHandle, PREC_UNARY);
|
||||||
|
|
||||||
//inverted booleans
|
//inverted booleans
|
||||||
if ((*root)->type == TOY_AST_VALUE && TOY_VALUE_IS_BOOLEAN((*root)->value.value)) {
|
if ((*rootHandle)->type == TOY_AST_VALUE && TOY_VALUE_IS_BOOLEAN((*rootHandle)->value.value)) {
|
||||||
(*root)->value.value = TOY_VALUE_TO_BOOLEAN( !TOY_VALUE_AS_BOOLEAN((*root)->value.value) );
|
(*rootHandle)->value.value = TOY_VALUE_TO_BOOLEAN( !TOY_VALUE_AS_BOOLEAN((*rootHandle)->value.value) );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
//actually emit the negation node
|
//actually emit the negation node
|
||||||
Toy_private_emitAstUnary(bucket, root, TOY_AST_FLAG_NEGATE);
|
Toy_private_emitAstUnary(bucketHandle, rootHandle, TOY_AST_FLAG_NEGATE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
printError(parser, parser->previous, "Unexpected token passed to unary precedence rule");
|
printError(parser, parser->previous, "Unexpected token passed to unary precedence rule");
|
||||||
Toy_private_emitAstError(bucket, root);
|
Toy_private_emitAstError(bucketHandle, rootHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TOY_AST_FLAG_NONE;
|
return TOY_AST_FLAG_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Toy_AstFlag binary(Toy_Bucket** bucket, Toy_Parser* parser, Toy_Ast** root) {
|
static Toy_AstFlag binary(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {
|
||||||
//infix must advance
|
//infix must advance
|
||||||
advance(parser);
|
advance(parser);
|
||||||
|
|
||||||
switch(parser->previous.type) {
|
switch(parser->previous.type) {
|
||||||
//arithmetic
|
//arithmetic
|
||||||
case TOY_TOKEN_OPERATOR_ADD: {
|
case TOY_TOKEN_OPERATOR_ADD: {
|
||||||
parsePrecedence(bucket, parser, root, PREC_TERM + 1);
|
parsePrecedence(bucketHandle, parser, rootHandle, PREC_TERM + 1);
|
||||||
return TOY_AST_FLAG_ADD;
|
return TOY_AST_FLAG_ADD;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_TOKEN_OPERATOR_SUBTRACT: {
|
case TOY_TOKEN_OPERATOR_SUBTRACT: {
|
||||||
parsePrecedence(bucket, parser, root, PREC_TERM + 1);
|
parsePrecedence(bucketHandle, parser, rootHandle, PREC_TERM + 1);
|
||||||
return TOY_AST_FLAG_SUBTRACT;
|
return TOY_AST_FLAG_SUBTRACT;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_TOKEN_OPERATOR_MULTIPLY: {
|
case TOY_TOKEN_OPERATOR_MULTIPLY: {
|
||||||
parsePrecedence(bucket, parser, root, PREC_FACTOR + 1);
|
parsePrecedence(bucketHandle, parser, rootHandle, PREC_FACTOR + 1);
|
||||||
return TOY_AST_FLAG_MULTIPLY;
|
return TOY_AST_FLAG_MULTIPLY;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_TOKEN_OPERATOR_DIVIDE: {
|
case TOY_TOKEN_OPERATOR_DIVIDE: {
|
||||||
parsePrecedence(bucket, parser, root, PREC_FACTOR + 1);
|
parsePrecedence(bucketHandle, parser, rootHandle, PREC_FACTOR + 1);
|
||||||
return TOY_AST_FLAG_DIVIDE;
|
return TOY_AST_FLAG_DIVIDE;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_TOKEN_OPERATOR_MODULO: {
|
case TOY_TOKEN_OPERATOR_MODULO: {
|
||||||
parsePrecedence(bucket, parser, root, PREC_FACTOR + 1);
|
parsePrecedence(bucketHandle, parser, rootHandle, PREC_FACTOR + 1);
|
||||||
return TOY_AST_FLAG_MODULO;
|
return TOY_AST_FLAG_MODULO;
|
||||||
}
|
}
|
||||||
|
|
||||||
//assignment
|
//assignment
|
||||||
case TOY_TOKEN_OPERATOR_ASSIGN: {
|
case TOY_TOKEN_OPERATOR_ASSIGN: {
|
||||||
parsePrecedence(bucket, parser, root, PREC_ASSIGNMENT + 1);
|
parsePrecedence(bucketHandle, parser, rootHandle, PREC_ASSIGNMENT + 1);
|
||||||
return TOY_AST_FLAG_ASSIGN;
|
return TOY_AST_FLAG_ASSIGN;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_TOKEN_OPERATOR_ADD_ASSIGN: {
|
case TOY_TOKEN_OPERATOR_ADD_ASSIGN: {
|
||||||
parsePrecedence(bucket, parser, root, PREC_ASSIGNMENT + 1);
|
parsePrecedence(bucketHandle, parser, rootHandle, PREC_ASSIGNMENT + 1);
|
||||||
return TOY_AST_FLAG_ADD_ASSIGN;
|
return TOY_AST_FLAG_ADD_ASSIGN;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_TOKEN_OPERATOR_SUBTRACT_ASSIGN: {
|
case TOY_TOKEN_OPERATOR_SUBTRACT_ASSIGN: {
|
||||||
parsePrecedence(bucket, parser, root, PREC_ASSIGNMENT + 1);
|
parsePrecedence(bucketHandle, parser, rootHandle, PREC_ASSIGNMENT + 1);
|
||||||
return TOY_AST_FLAG_SUBTRACT_ASSIGN;
|
return TOY_AST_FLAG_SUBTRACT_ASSIGN;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_TOKEN_OPERATOR_MULTIPLY_ASSIGN: {
|
case TOY_TOKEN_OPERATOR_MULTIPLY_ASSIGN: {
|
||||||
parsePrecedence(bucket, parser, root, PREC_ASSIGNMENT + 1);
|
parsePrecedence(bucketHandle, parser, rootHandle, PREC_ASSIGNMENT + 1);
|
||||||
return TOY_AST_FLAG_MULTIPLY_ASSIGN;
|
return TOY_AST_FLAG_MULTIPLY_ASSIGN;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_TOKEN_OPERATOR_DIVIDE_ASSIGN: {
|
case TOY_TOKEN_OPERATOR_DIVIDE_ASSIGN: {
|
||||||
parsePrecedence(bucket, parser, root, PREC_ASSIGNMENT + 1);
|
parsePrecedence(bucketHandle, parser, rootHandle, PREC_ASSIGNMENT + 1);
|
||||||
return TOY_AST_FLAG_DIVIDE_ASSIGN;
|
return TOY_AST_FLAG_DIVIDE_ASSIGN;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_TOKEN_OPERATOR_MODULO_ASSIGN: {
|
case TOY_TOKEN_OPERATOR_MODULO_ASSIGN: {
|
||||||
parsePrecedence(bucket, parser, root, PREC_ASSIGNMENT + 1);
|
parsePrecedence(bucketHandle, parser, rootHandle, PREC_ASSIGNMENT + 1);
|
||||||
return TOY_AST_FLAG_MODULO_ASSIGN;
|
return TOY_AST_FLAG_MODULO_ASSIGN;
|
||||||
}
|
}
|
||||||
|
|
||||||
//comparison
|
//comparison
|
||||||
case TOY_TOKEN_OPERATOR_COMPARE_EQUAL: {
|
case TOY_TOKEN_OPERATOR_COMPARE_EQUAL: {
|
||||||
parsePrecedence(bucket, parser, root, PREC_COMPARISON + 1);
|
parsePrecedence(bucketHandle, parser, rootHandle, PREC_COMPARISON + 1);
|
||||||
return TOY_AST_FLAG_COMPARE_EQUAL;
|
return TOY_AST_FLAG_COMPARE_EQUAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_TOKEN_OPERATOR_COMPARE_NOT: {
|
case TOY_TOKEN_OPERATOR_COMPARE_NOT: {
|
||||||
parsePrecedence(bucket, parser, root, PREC_COMPARISON + 1);
|
parsePrecedence(bucketHandle, parser, rootHandle, PREC_COMPARISON + 1);
|
||||||
return TOY_AST_FLAG_COMPARE_NOT;
|
return TOY_AST_FLAG_COMPARE_NOT;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_TOKEN_OPERATOR_COMPARE_LESS: {
|
case TOY_TOKEN_OPERATOR_COMPARE_LESS: {
|
||||||
parsePrecedence(bucket, parser, root, PREC_COMPARISON + 1);
|
parsePrecedence(bucketHandle, parser, rootHandle, PREC_COMPARISON + 1);
|
||||||
return TOY_AST_FLAG_COMPARE_LESS;
|
return TOY_AST_FLAG_COMPARE_LESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_TOKEN_OPERATOR_COMPARE_LESS_EQUAL: {
|
case TOY_TOKEN_OPERATOR_COMPARE_LESS_EQUAL: {
|
||||||
parsePrecedence(bucket, parser, root, PREC_COMPARISON + 1);
|
parsePrecedence(bucketHandle, parser, rootHandle, PREC_COMPARISON + 1);
|
||||||
return TOY_AST_FLAG_COMPARE_LESS_EQUAL;
|
return TOY_AST_FLAG_COMPARE_LESS_EQUAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_TOKEN_OPERATOR_COMPARE_GREATER: {
|
case TOY_TOKEN_OPERATOR_COMPARE_GREATER: {
|
||||||
parsePrecedence(bucket, parser, root, PREC_COMPARISON + 1);
|
parsePrecedence(bucketHandle, parser, rootHandle, PREC_COMPARISON + 1);
|
||||||
return TOY_AST_FLAG_COMPARE_GREATER;
|
return TOY_AST_FLAG_COMPARE_GREATER;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOY_TOKEN_OPERATOR_COMPARE_GREATER_EQUAL: {
|
case TOY_TOKEN_OPERATOR_COMPARE_GREATER_EQUAL: {
|
||||||
parsePrecedence(bucket, parser, root, PREC_COMPARISON + 1);
|
parsePrecedence(bucketHandle, parser, rootHandle, PREC_COMPARISON + 1);
|
||||||
return TOY_AST_FLAG_COMPARE_GREATER_EQUAL;
|
return TOY_AST_FLAG_COMPARE_GREATER_EQUAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
printError(parser, parser->previous, "Unexpected token passed to binary precedence rule");
|
printError(parser, parser->previous, "Unexpected token passed to binary precedence rule");
|
||||||
Toy_private_emitAstError(bucket, root);
|
Toy_private_emitAstError(bucketHandle, rootHandle);
|
||||||
return TOY_AST_FLAG_NONE;
|
return TOY_AST_FLAG_NONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Toy_AstFlag group(Toy_Bucket** bucket, Toy_Parser* parser, Toy_Ast** root) {
|
static Toy_AstFlag group(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {
|
||||||
//groups are ()
|
//groups are ()
|
||||||
if (parser->previous.type == TOY_TOKEN_OPERATOR_PAREN_LEFT) {
|
if (parser->previous.type == TOY_TOKEN_OPERATOR_PAREN_LEFT) {
|
||||||
parsePrecedence(bucket, parser, root, PREC_GROUP);
|
parsePrecedence(bucketHandle, parser, rootHandle, PREC_GROUP);
|
||||||
consume(parser, TOY_TOKEN_OPERATOR_PAREN_RIGHT, "Expected ')' at end of group");
|
consume(parser, TOY_TOKEN_OPERATOR_PAREN_RIGHT, "Expected ')' at end of group");
|
||||||
|
|
||||||
//Toy_AstGroup is omitted from generation, as an optimisation
|
//Toy_AstGroup is omitted from generation, as an optimisation
|
||||||
// Toy_private_emitAstGroup(bucket, root);
|
// Toy_private_emitAstGroup(bucketHandle, rootHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
printError(parser, parser->previous, "Unexpected token passed to grouping precedence rule");
|
printError(parser, parser->previous, "Unexpected token passed to grouping precedence rule");
|
||||||
Toy_private_emitAstError(bucket, root);
|
Toy_private_emitAstError(bucketHandle, rootHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TOY_AST_FLAG_NONE;
|
return TOY_AST_FLAG_NONE;
|
||||||
@@ -435,7 +435,7 @@ static ParsingTuple* getParsingRule(Toy_TokenType type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//grammar rules
|
//grammar rules
|
||||||
static void parsePrecedence(Toy_Bucket** bucket, Toy_Parser* parser, Toy_Ast** root, ParsingPrecedence precRule) {
|
static void parsePrecedence(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle, ParsingPrecedence precRule) {
|
||||||
//'step over' the token to parse
|
//'step over' the token to parse
|
||||||
advance(parser);
|
advance(parser);
|
||||||
|
|
||||||
@@ -444,11 +444,11 @@ static void parsePrecedence(Toy_Bucket** bucket, Toy_Parser* parser, Toy_Ast** r
|
|||||||
|
|
||||||
if (prefix == NULL) {
|
if (prefix == NULL) {
|
||||||
printError(parser, parser->previous, "Expected expression");
|
printError(parser, parser->previous, "Expected expression");
|
||||||
Toy_private_emitAstError(bucket, root);
|
Toy_private_emitAstError(bucketHandle, rootHandle);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
prefix(bucket, parser, root);
|
prefix(bucketHandle, parser, rootHandle);
|
||||||
|
|
||||||
//infix rules are left-recursive
|
//infix rules are left-recursive
|
||||||
while (precRule <= getParsingRule(parser->current.type)->precedence) {
|
while (precRule <= getParsingRule(parser->current.type)->precedence) {
|
||||||
@@ -456,20 +456,20 @@ static void parsePrecedence(Toy_Bucket** bucket, Toy_Parser* parser, Toy_Ast** r
|
|||||||
|
|
||||||
if (infix == NULL) {
|
if (infix == NULL) {
|
||||||
printError(parser, parser->previous, "Expected operator");
|
printError(parser, parser->previous, "Expected operator");
|
||||||
Toy_private_emitAstError(bucket, root);
|
Toy_private_emitAstError(bucketHandle, rootHandle);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Toy_Ast* ptr = NULL;
|
Toy_Ast* ptr = NULL;
|
||||||
Toy_AstFlag flag = infix(bucket, parser, &ptr);
|
Toy_AstFlag flag = infix(bucketHandle, parser, &ptr);
|
||||||
|
|
||||||
//finished
|
//finished
|
||||||
if (flag == TOY_AST_FLAG_NONE) {
|
if (flag == TOY_AST_FLAG_NONE) {
|
||||||
(*root) = ptr;
|
(*rootHandle) = ptr;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Toy_private_emitAstBinary(bucket, root, flag, ptr);
|
Toy_private_emitAstBinary(bucketHandle, rootHandle, flag, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
//can't assign below a certain precedence
|
//can't assign below a certain precedence
|
||||||
@@ -478,22 +478,22 @@ static void parsePrecedence(Toy_Bucket** bucket, Toy_Parser* parser, Toy_Ast** r
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void makeExpr(Toy_Bucket** bucket, Toy_Parser* parser, Toy_Ast** root) {
|
static void makeExpr(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {
|
||||||
parsePrecedence(bucket, parser, root, PREC_ASSIGNMENT);
|
parsePrecedence(bucketHandle, parser, rootHandle, PREC_ASSIGNMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void makeExprStmt(Toy_Bucket** bucket, Toy_Parser* parser, Toy_Ast** root) {
|
static void makeExprStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {
|
||||||
//check for empty lines
|
//check for empty lines
|
||||||
if (match(parser, TOY_TOKEN_OPERATOR_SEMICOLON)) {
|
if (match(parser, TOY_TOKEN_OPERATOR_SEMICOLON)) {
|
||||||
Toy_private_emitAstPass(bucket, root);
|
Toy_private_emitAstPass(bucketHandle, rootHandle);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
makeExpr(bucket, parser, root);
|
makeExpr(bucketHandle, parser, rootHandle);
|
||||||
consume(parser, TOY_TOKEN_OPERATOR_SEMICOLON, "Expected ';' at the end of expression statement");
|
consume(parser, TOY_TOKEN_OPERATOR_SEMICOLON, "Expected ';' at the end of expression statement");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void makeStmt(Toy_Bucket** bucket, Toy_Parser* parser, Toy_Ast** root) {
|
static void makeStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {
|
||||||
//block
|
//block
|
||||||
//print
|
//print
|
||||||
//assert
|
//assert
|
||||||
@@ -506,47 +506,47 @@ static void makeStmt(Toy_Bucket** bucket, Toy_Parser* parser, Toy_Ast** root) {
|
|||||||
//import
|
//import
|
||||||
|
|
||||||
//default
|
//default
|
||||||
makeExprStmt(bucket, parser, root);
|
makeExprStmt(bucketHandle, parser, rootHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void makeDeclarationStmt(Toy_Bucket** bucket, Toy_Parser* parser, Toy_Ast** root) {
|
static void makeDeclarationStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {
|
||||||
// //variable declarations
|
// //variable declarations
|
||||||
// if (match(parser, TOY_TOKEN_KEYWORD_VAR)) {
|
// if (match(parser, TOY_TOKEN_KEYWORD_VAR)) {
|
||||||
// makeVariableDeclarationStmt(bucket, parser, root);
|
// makeVariableDeclarationStmt(bucketHandle, parser, rootHandle);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// //function declarations
|
// //function declarations
|
||||||
// else if (match(parser, TOY_TOKEN_KEYWORD_FUNCTION)) {
|
// else if (match(parser, TOY_TOKEN_KEYWORD_FUNCTION)) {
|
||||||
// makeFunctionDeclarationStmt(bucket, parser, root);
|
// makeFunctionDeclarationStmt(bucketHandle, parser, rootHandle);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
//otherwise
|
//otherwise
|
||||||
// else {
|
// else {
|
||||||
makeStmt(bucket, parser, root);
|
makeStmt(bucketHandle, parser, rootHandle);
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
static void makeBlockStmt(Toy_Bucket** bucket, Toy_Parser* parser, Toy_Ast** root) {
|
static void makeBlockStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {
|
||||||
//begin the block
|
//begin the block
|
||||||
Toy_private_initAstBlock(bucket, root);
|
Toy_private_initAstBlock(bucketHandle, rootHandle);
|
||||||
|
|
||||||
//read a series of statements into the block
|
//read a series of statements into the block
|
||||||
while (!match(parser, TOY_TOKEN_EOF)) {
|
while (!match(parser, TOY_TOKEN_EOF)) {
|
||||||
//process the grammar rules
|
//process the grammar rules
|
||||||
Toy_Ast* stmt = NULL;
|
Toy_Ast* stmt = NULL;
|
||||||
makeDeclarationStmt(bucket, parser, &stmt);
|
makeDeclarationStmt(bucketHandle, parser, &stmt);
|
||||||
|
|
||||||
//if something went wrong
|
//if something went wrong
|
||||||
if (parser->panic) {
|
if (parser->panic) {
|
||||||
synchronize(parser);
|
synchronize(parser);
|
||||||
|
|
||||||
Toy_Ast* err = NULL;
|
Toy_Ast* err = NULL;
|
||||||
Toy_private_emitAstError(bucket, &err);
|
Toy_private_emitAstError(bucketHandle, &err);
|
||||||
Toy_private_appendAstBlock(bucket, *root, err);
|
Toy_private_appendAstBlock(bucketHandle, *rootHandle, err);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Toy_private_appendAstBlock(bucket, *root, stmt);
|
Toy_private_appendAstBlock(bucketHandle, *rootHandle, stmt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -557,18 +557,18 @@ void Toy_bindParser(Toy_Parser* parser, Toy_Lexer* lexer) {
|
|||||||
advance(parser);
|
advance(parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
Toy_Ast* Toy_scanParser(Toy_Bucket** bucket, Toy_Parser* parser) {
|
Toy_Ast* Toy_scanParser(Toy_Bucket** bucketHandle, Toy_Parser* parser) {
|
||||||
Toy_Ast* root = NULL;
|
Toy_Ast* rootHandle = NULL;
|
||||||
|
|
||||||
//check for EOF
|
//check for EOF
|
||||||
if (match(parser, TOY_TOKEN_EOF)) {
|
if (match(parser, TOY_TOKEN_EOF)) {
|
||||||
Toy_private_emitAstEnd(bucket, &root);
|
Toy_private_emitAstEnd(bucketHandle, &rootHandle);
|
||||||
return root;
|
return rootHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
makeBlockStmt(bucket, parser, &root);
|
makeBlockStmt(bucketHandle, parser, &rootHandle);
|
||||||
|
|
||||||
return root;
|
return rootHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Toy_resetParser(Toy_Parser* parser) {
|
void Toy_resetParser(Toy_Parser* parser) {
|
||||||
|
|||||||
@@ -17,5 +17,5 @@ typedef struct Toy_Parser {
|
|||||||
} Toy_Parser;
|
} Toy_Parser;
|
||||||
|
|
||||||
TOY_API void Toy_bindParser(Toy_Parser* parser, Toy_Lexer* lexer);
|
TOY_API void Toy_bindParser(Toy_Parser* parser, Toy_Lexer* lexer);
|
||||||
TOY_API Toy_Ast* Toy_scanParser(Toy_Bucket** bucket, Toy_Parser* parser);
|
TOY_API Toy_Ast* Toy_scanParser(Toy_Bucket** bucketHandle, Toy_Parser* parser);
|
||||||
TOY_API void Toy_resetParser(Toy_Parser* parser);
|
TOY_API void Toy_resetParser(Toy_Parser* parser);
|
||||||
|
|||||||
@@ -27,60 +27,60 @@ void Toy_freeStack(Toy_Stack* stack) {
|
|||||||
free(stack);
|
free(stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Toy_pushStack(Toy_Stack** stack, Toy_Value value) {
|
void Toy_pushStack(Toy_Stack** stackHandle, Toy_Value value) {
|
||||||
//don't go overboard - limit to 1mb of capacity used
|
//don't go overboard - limit to 1mb of capacity used
|
||||||
if ((*stack)->count >= 1024 * 1024 / sizeof(Toy_Value)) {
|
if ((*stackHandle)->count >= 1024 * 1024 / sizeof(Toy_Value)) {
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Stack overflow\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Stack overflow\n" TOY_CC_RESET);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
//expand the capacity if needed
|
//expand the capacity if needed
|
||||||
if ((*stack)->count + 1 > (*stack)->capacity) {
|
if ((*stackHandle)->count + 1 > (*stackHandle)->capacity) {
|
||||||
while ((*stack)->count + 1 > (*stack)->capacity) {
|
while ((*stackHandle)->count + 1 > (*stackHandle)->capacity) {
|
||||||
(*stack)->capacity = (*stack)->capacity < MIN_CAPACITY ? MIN_CAPACITY : (*stack)->capacity * 2;
|
(*stackHandle)->capacity = (*stackHandle)->capacity < MIN_CAPACITY ? MIN_CAPACITY : (*stackHandle)->capacity * 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int newCapacity = (*stack)->capacity;
|
unsigned int newCapacity = (*stackHandle)->capacity;
|
||||||
|
|
||||||
(*stack) = realloc((*stack), newCapacity * sizeof(Toy_Value) + sizeof(Toy_Stack));
|
(*stackHandle) = realloc((*stackHandle), newCapacity * sizeof(Toy_Value) + sizeof(Toy_Stack));
|
||||||
|
|
||||||
if ((*stack) == NULL) {
|
if ((*stackHandle) == NULL) {
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to reallocate a 'Toy_Stack' of %d capacity (%d space in memory)\n" TOY_CC_RESET, (int)newCapacity, (int)(newCapacity * sizeof(Toy_Value) + sizeof(Toy_Stack)));
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to reallocate a 'Toy_Stack' of %d capacity (%d space in memory)\n" TOY_CC_RESET, (int)newCapacity, (int)(newCapacity * sizeof(Toy_Value) + sizeof(Toy_Stack)));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Note: "pointer arithmetic in C/C++ is type-relative"
|
//Note: "pointer arithmetic in C/C++ is type-relative"
|
||||||
((Toy_Value*)((*stack) + 1))[(*stack)->count++] = value;
|
((Toy_Value*)((*stackHandle) + 1))[(*stackHandle)->count++] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Toy_Value Toy_peekStack(Toy_Stack** stack) {
|
Toy_Value Toy_peekStack(Toy_Stack** stackHandle) {
|
||||||
if ((*stack)->count == 0) {
|
if ((*stackHandle)->count == 0) {
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Stack underflow\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Stack underflow\n" TOY_CC_RESET);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ((Toy_Value*)((*stack) + 1))[(*stack)->count - 1];
|
return ((Toy_Value*)((*stackHandle) + 1))[(*stackHandle)->count - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
Toy_Value Toy_popStack(Toy_Stack** stack) {
|
Toy_Value Toy_popStack(Toy_Stack** stackHandle) {
|
||||||
if ((*stack)->count == 0) {
|
if ((*stackHandle)->count == 0) {
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Stack underflow\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Stack underflow\n" TOY_CC_RESET);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
//shrink if possible
|
//shrink if possible
|
||||||
if ((*stack)->count > MIN_CAPACITY && (*stack)->count < (*stack)->capacity / 4) {
|
if ((*stackHandle)->count > MIN_CAPACITY && (*stackHandle)->count < (*stackHandle)->capacity / 4) {
|
||||||
(*stack)->capacity /= 2;
|
(*stackHandle)->capacity /= 2;
|
||||||
unsigned int newCapacity = (*stack)->capacity;
|
unsigned int newCapacity = (*stackHandle)->capacity;
|
||||||
|
|
||||||
(*stack) = realloc((*stack), (*stack)->capacity * sizeof(Toy_Value) + sizeof(Toy_Stack));
|
(*stackHandle) = realloc((*stackHandle), (*stackHandle)->capacity * sizeof(Toy_Value) + sizeof(Toy_Stack));
|
||||||
|
|
||||||
if ((*stack) == NULL) {
|
if ((*stackHandle) == NULL) {
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to reallocate a 'Toy_Stack' of %d capacity (%d space in memory)\n" TOY_CC_RESET, (int)newCapacity, (int)(newCapacity * sizeof(Toy_Value) + sizeof(Toy_Stack)));
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to reallocate a 'Toy_Stack' of %d capacity (%d space in memory)\n" TOY_CC_RESET, (int)newCapacity, (int)(newCapacity * sizeof(Toy_Value) + sizeof(Toy_Stack)));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ((Toy_Value*)((*stack) + 1))[--(*stack)->count];
|
return ((Toy_Value*)((*stackHandle) + 1))[--(*stackHandle)->count];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,6 @@ typedef struct Toy_Stack { //32 | 64 BITNESS
|
|||||||
TOY_API Toy_Stack* Toy_allocateStack();
|
TOY_API Toy_Stack* Toy_allocateStack();
|
||||||
TOY_API void Toy_freeStack(Toy_Stack* stack);
|
TOY_API void Toy_freeStack(Toy_Stack* stack);
|
||||||
|
|
||||||
TOY_API void Toy_pushStack(Toy_Stack** stack, Toy_Value value);
|
TOY_API void Toy_pushStack(Toy_Stack** stackHandle, Toy_Value value);
|
||||||
TOY_API Toy_Value Toy_peekStack(Toy_Stack** stack);
|
TOY_API Toy_Value Toy_peekStack(Toy_Stack** stackHandle);
|
||||||
TOY_API Toy_Value Toy_popStack(Toy_Stack** stack);
|
TOY_API Toy_Value Toy_popStack(Toy_Stack** stackHandle);
|
||||||
|
|||||||
@@ -35,14 +35,14 @@ static void decrementRefCount(Toy_String* str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//exposed functions
|
//exposed functions
|
||||||
Toy_String* Toy_createString(Toy_Bucket** bucket, const char* cstring) {
|
Toy_String* Toy_createString(Toy_Bucket** bucketHandle, const char* cstring) {
|
||||||
int length = strlen(cstring);
|
int length = strlen(cstring);
|
||||||
|
|
||||||
return Toy_createStringLength(bucket, cstring, length);
|
return Toy_createStringLength(bucketHandle, cstring, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
Toy_String* Toy_createStringLength(Toy_Bucket** bucket, const char* cstring, int length) {
|
Toy_String* Toy_createStringLength(Toy_Bucket** bucketHandle, const char* cstring, int length) {
|
||||||
Toy_String* ret = (Toy_String*)Toy_partitionBucket(bucket, sizeof(Toy_String) + length + 1); //TODO: compensate for partitioning more space than bucket capacity
|
Toy_String* ret = (Toy_String*)Toy_partitionBucket(bucketHandle, sizeof(Toy_String) + length + 1); //TODO: compensate for partitioning more space than bucket capacity
|
||||||
|
|
||||||
ret->type = TOY_STRING_LEAF;
|
ret->type = TOY_STRING_LEAF;
|
||||||
ret->length = length;
|
ret->length = length;
|
||||||
@@ -53,7 +53,7 @@ Toy_String* Toy_createStringLength(Toy_Bucket** bucket, const char* cstring, int
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Toy_String* Toy_copyString(Toy_Bucket** bucket, Toy_String* str) {
|
Toy_String* Toy_copyString(Toy_Bucket** bucketHandle, Toy_String* str) {
|
||||||
if (str->refCount == 0) {
|
if (str->refCount == 0) {
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Can't copy a string with refcount of zero\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Can't copy a string with refcount of zero\n" TOY_CC_RESET);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
@@ -62,12 +62,12 @@ Toy_String* Toy_copyString(Toy_Bucket** bucket, Toy_String* str) {
|
|||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
Toy_String* Toy_deepCopyString(Toy_Bucket** bucket, Toy_String* str) {
|
Toy_String* Toy_deepCopyString(Toy_Bucket** bucketHandle, Toy_String* str) {
|
||||||
if (str->refCount == 0) {
|
if (str->refCount == 0) {
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Can't deep copy a string with refcount of zero\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Can't deep copy a string with refcount of zero\n" TOY_CC_RESET);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
Toy_String* ret = (Toy_String*)Toy_partitionBucket(bucket, sizeof(Toy_String) + str->length + 1); //TODO: compensate for partitioning more space than bucket capacity
|
Toy_String* ret = (Toy_String*)Toy_partitionBucket(bucketHandle, sizeof(Toy_String) + str->length + 1); //TODO: compensate for partitioning more space than bucket capacity
|
||||||
|
|
||||||
//
|
//
|
||||||
ret->type = TOY_STRING_LEAF;
|
ret->type = TOY_STRING_LEAF;
|
||||||
@@ -79,13 +79,13 @@ Toy_String* Toy_deepCopyString(Toy_Bucket** bucket, Toy_String* str) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Toy_String* Toy_concatString(Toy_Bucket** bucket, Toy_String* left, Toy_String* right) {
|
Toy_String* Toy_concatString(Toy_Bucket** bucketHandle, Toy_String* left, Toy_String* right) {
|
||||||
if (left->refCount == 0 || right->refCount == 0) {
|
if (left->refCount == 0 || right->refCount == 0) {
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Can't concatenate a string with refcount of zero\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Can't concatenate a string with refcount of zero\n" TOY_CC_RESET);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Toy_String* ret = (Toy_String*)Toy_partitionBucket(bucket, sizeof(Toy_String));
|
Toy_String* ret = (Toy_String*)Toy_partitionBucket(bucketHandle, sizeof(Toy_String));
|
||||||
|
|
||||||
ret->type = TOY_STRING_NODE;
|
ret->type = TOY_STRING_NODE;
|
||||||
ret->length = left->length + right->length;
|
ret->length = left->length + right->length;
|
||||||
|
|||||||
@@ -27,13 +27,13 @@ typedef struct Toy_String { //32 | 64 BITNESS
|
|||||||
} as; //8 | 16
|
} as; //8 | 16
|
||||||
} Toy_String; //24 | 32
|
} Toy_String; //24 | 32
|
||||||
|
|
||||||
TOY_API Toy_String* Toy_createString(Toy_Bucket** bucket, const char* cstring);
|
TOY_API Toy_String* Toy_createString(Toy_Bucket** bucketHandle, const char* cstring);
|
||||||
TOY_API Toy_String* Toy_createStringLength(Toy_Bucket** bucket, const char* cstring, int length);
|
TOY_API Toy_String* Toy_createStringLength(Toy_Bucket** bucketHandle, const char* cstring, int length);
|
||||||
|
|
||||||
TOY_API Toy_String* Toy_copyString(Toy_Bucket** bucket, Toy_String* str);
|
TOY_API Toy_String* Toy_copyString(Toy_Bucket** bucketHandle, Toy_String* str);
|
||||||
TOY_API Toy_String* Toy_deepCopyString(Toy_Bucket** bucket, Toy_String* str);
|
TOY_API Toy_String* Toy_deepCopyString(Toy_Bucket** bucketHandle, Toy_String* str);
|
||||||
|
|
||||||
TOY_API Toy_String* Toy_concatString(Toy_Bucket** bucket, Toy_String* left, Toy_String* right);
|
TOY_API Toy_String* Toy_concatString(Toy_Bucket** bucketHandle, Toy_String* left, Toy_String* right);
|
||||||
|
|
||||||
TOY_API void Toy_freeString(Toy_String* str);
|
TOY_API void Toy_freeString(Toy_String* str);
|
||||||
|
|
||||||
|
|||||||
@@ -9,46 +9,46 @@
|
|||||||
#define MIN_CAPACITY 16
|
#define MIN_CAPACITY 16
|
||||||
|
|
||||||
//utils
|
//utils
|
||||||
static void probeAndInsert(Toy_Table** table, Toy_Value key, Toy_Value value) {
|
static void probeAndInsert(Toy_Table** tableHandle, Toy_Value key, Toy_Value value) {
|
||||||
//make the entry
|
//make the entry
|
||||||
unsigned int probe = Toy_hashValue(key) % (*table)->capacity;
|
unsigned int probe = Toy_hashValue(key) % (*tableHandle)->capacity;
|
||||||
Toy_TableEntry entry = (Toy_TableEntry){ .key = key, .value = value, .psl = 0 };
|
Toy_TableEntry entry = (Toy_TableEntry){ .key = key, .value = value, .psl = 0 };
|
||||||
|
|
||||||
//probe
|
//probe
|
||||||
while (true) {
|
while (true) {
|
||||||
//if we're overriding an existing value
|
//if we're overriding an existing value
|
||||||
if (TOY_VALUE_IS_EQUAL((*table)->data[probe].key, key)) {
|
if (TOY_VALUE_IS_EQUAL((*tableHandle)->data[probe].key, key)) {
|
||||||
(*table)->data[probe] = entry;
|
(*tableHandle)->data[probe] = entry;
|
||||||
|
|
||||||
//TODO: benchmark the psl optimisation
|
//TODO: benchmark the psl optimisation
|
||||||
(*table)->minPsl = entry.psl < (*table)->minPsl ? entry.psl : (*table)->minPsl;
|
(*tableHandle)->minPsl = entry.psl < (*tableHandle)->minPsl ? entry.psl : (*tableHandle)->minPsl;
|
||||||
(*table)->maxPsl = entry.psl > (*table)->maxPsl ? entry.psl : (*table)->maxPsl;
|
(*tableHandle)->maxPsl = entry.psl > (*tableHandle)->maxPsl ? entry.psl : (*tableHandle)->maxPsl;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//if this spot is free, insert and return
|
//if this spot is free, insert and return
|
||||||
if (TOY_VALUE_IS_NULL((*table)->data[probe].key)) {
|
if (TOY_VALUE_IS_NULL((*tableHandle)->data[probe].key)) {
|
||||||
(*table)->data[probe] = entry;
|
(*tableHandle)->data[probe] = entry;
|
||||||
|
|
||||||
(*table)->count++;
|
(*tableHandle)->count++;
|
||||||
|
|
||||||
//TODO: benchmark the psl optimisation
|
//TODO: benchmark the psl optimisation
|
||||||
(*table)->minPsl = entry.psl < (*table)->minPsl ? entry.psl : (*table)->minPsl;
|
(*tableHandle)->minPsl = entry.psl < (*tableHandle)->minPsl ? entry.psl : (*tableHandle)->minPsl;
|
||||||
(*table)->maxPsl = entry.psl > (*table)->maxPsl ? entry.psl : (*table)->maxPsl;
|
(*tableHandle)->maxPsl = entry.psl > (*tableHandle)->maxPsl ? entry.psl : (*tableHandle)->maxPsl;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//if the new entry is "poorer", insert it and shift the old one
|
//if the new entry is "poorer", insert it and shift the old one
|
||||||
if ((*table)->data[probe].psl < entry.psl) {
|
if ((*tableHandle)->data[probe].psl < entry.psl) {
|
||||||
Toy_TableEntry tmp = (*table)->data[probe];
|
Toy_TableEntry tmp = (*tableHandle)->data[probe];
|
||||||
(*table)->data[probe] = entry;
|
(*tableHandle)->data[probe] = entry;
|
||||||
entry = tmp;
|
entry = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
//adjust and continue
|
//adjust and continue
|
||||||
probe = (probe + 1) % (*table)->capacity;
|
probe = (probe + 1) % (*tableHandle)->capacity;
|
||||||
entry.psl++;
|
entry.psl++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -97,86 +97,86 @@ void Toy_freeTable(Toy_Table* table) {
|
|||||||
free(table);
|
free(table);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Toy_insertTable(Toy_Table** table, Toy_Value key, Toy_Value value) {
|
void Toy_insertTable(Toy_Table** tableHandle, Toy_Value key, Toy_Value value) {
|
||||||
if (TOY_VALUE_IS_NULL(key) || TOY_VALUE_IS_BOOLEAN(key)) { //TODO: disallow functions and opaques
|
if (TOY_VALUE_IS_NULL(key) || TOY_VALUE_IS_BOOLEAN(key)) { //TODO: disallow functions and opaques
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Bad table key\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Bad table key\n" TOY_CC_RESET);
|
||||||
exit(-1); //TODO: #127
|
exit(-1); //TODO: #127
|
||||||
}
|
}
|
||||||
|
|
||||||
//expand the capacity
|
//expand the capacity
|
||||||
if ((*table)->count > (*table)->capacity * 0.8) {
|
if ((*tableHandle)->count > (*tableHandle)->capacity * 0.8) {
|
||||||
(*table) = adjustTableCapacity(*table, (*table)->capacity * 2);
|
(*tableHandle) = adjustTableCapacity((*tableHandle), (*tableHandle)->capacity * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
probeAndInsert(table, key, value);
|
probeAndInsert(tableHandle, key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Toy_Value Toy_lookupTable(Toy_Table** table, Toy_Value key) {
|
Toy_Value Toy_lookupTable(Toy_Table** tableHandle, Toy_Value key) {
|
||||||
if (TOY_VALUE_IS_NULL(key) || TOY_VALUE_IS_BOOLEAN(key)) { //TODO: disallow functions and opaques
|
if (TOY_VALUE_IS_NULL(key) || TOY_VALUE_IS_BOOLEAN(key)) { //TODO: disallow functions and opaques
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Bad table key\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Bad table key\n" TOY_CC_RESET);
|
||||||
exit(-1); //TODO: #127
|
exit(-1); //TODO: #127
|
||||||
}
|
}
|
||||||
|
|
||||||
//lookup
|
//lookup
|
||||||
unsigned int probe = Toy_hashValue(key) % (*table)->capacity;
|
unsigned int probe = Toy_hashValue(key) % (*tableHandle)->capacity;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
//found the entry
|
//found the entry
|
||||||
if (TOY_VALUE_IS_EQUAL((*table)->data[probe].key, key)) {
|
if (TOY_VALUE_IS_EQUAL((*tableHandle)->data[probe].key, key)) {
|
||||||
return (*table)->data[probe].value;
|
return (*tableHandle)->data[probe].value;
|
||||||
}
|
}
|
||||||
|
|
||||||
//if its an empty slot
|
//if its an empty slot
|
||||||
if (TOY_VALUE_IS_NULL((*table)->data[probe].key)) {
|
if (TOY_VALUE_IS_NULL((*tableHandle)->data[probe].key)) {
|
||||||
return TOY_VALUE_TO_NULL();
|
return TOY_VALUE_TO_NULL();
|
||||||
}
|
}
|
||||||
|
|
||||||
//adjust and continue
|
//adjust and continue
|
||||||
probe = (probe + 1) % (*table)->capacity;
|
probe = (probe + 1) % (*tableHandle)->capacity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Toy_removeTable(Toy_Table** table, Toy_Value key) {
|
void Toy_removeTable(Toy_Table** tableHandle, Toy_Value key) {
|
||||||
if (TOY_VALUE_IS_NULL(key) || TOY_VALUE_IS_BOOLEAN(key)) { //TODO: disallow functions and opaques
|
if (TOY_VALUE_IS_NULL(key) || TOY_VALUE_IS_BOOLEAN(key)) { //TODO: disallow functions and opaques
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Bad table key\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Bad table key\n" TOY_CC_RESET);
|
||||||
exit(-1); //TODO: #127
|
exit(-1); //TODO: #127
|
||||||
}
|
}
|
||||||
|
|
||||||
//lookup
|
//lookup
|
||||||
unsigned int probe = Toy_hashValue(key) % (*table)->capacity;
|
unsigned int probe = Toy_hashValue(key) % (*tableHandle)->capacity;
|
||||||
unsigned int wipe = probe; //wiped at the end
|
unsigned int wipe = probe; //wiped at the end
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
//found the entry
|
//found the entry
|
||||||
if (TOY_VALUE_IS_EQUAL((*table)->data[probe].key, key)) {
|
if (TOY_VALUE_IS_EQUAL((*tableHandle)->data[probe].key, key)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
//if its an empty slot
|
//if its an empty slot
|
||||||
if (TOY_VALUE_IS_NULL((*table)->data[probe].key)) {
|
if (TOY_VALUE_IS_NULL((*tableHandle)->data[probe].key)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//adjust and continue
|
//adjust and continue
|
||||||
probe = (probe + 1) % (*table)->capacity;
|
probe = (probe + 1) % (*tableHandle)->capacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
//shift along the later entries
|
//shift along the later entries
|
||||||
for (unsigned int i = (*table)->minPsl; i < (*table)->maxPsl; i++) {
|
for (unsigned int i = (*tableHandle)->minPsl; i < (*tableHandle)->maxPsl; i++) {
|
||||||
unsigned int p = (probe + i + 0) % (*table)->capacity; //prev
|
unsigned int p = (probe + i + 0) % (*tableHandle)->capacity; //prev
|
||||||
unsigned int u = (probe + i + 1) % (*table)->capacity; //current
|
unsigned int u = (probe + i + 1) % (*tableHandle)->capacity; //current
|
||||||
|
|
||||||
(*table)->data[p] = (*table)->data[u];
|
(*tableHandle)->data[p] = (*tableHandle)->data[u];
|
||||||
(*table)->data[p].psl--;
|
(*tableHandle)->data[p].psl--;
|
||||||
|
|
||||||
//if you hit something where it should be, or nothing at all, stop
|
//if you hit something where it should be, or nothing at all, stop
|
||||||
if (TOY_VALUE_IS_NULL((*table)->data[u].key) || (*table)->data[p].psl == 0) {
|
if (TOY_VALUE_IS_NULL((*tableHandle)->data[u].key) || (*tableHandle)->data[p].psl == 0) {
|
||||||
wipe = u;
|
wipe = u;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//finally, wipe the removed entry
|
//finally, wipe the removed entry
|
||||||
(*table)->data[wipe] = (Toy_TableEntry){ .key = TOY_VALUE_TO_NULL(), .value = TOY_VALUE_TO_NULL(), .psl = 0 };
|
(*tableHandle)->data[wipe] = (Toy_TableEntry){ .key = TOY_VALUE_TO_NULL(), .value = TOY_VALUE_TO_NULL(), .psl = 0 };
|
||||||
(*table)->count--;
|
(*tableHandle)->count--;
|
||||||
}
|
}
|
||||||
@@ -22,6 +22,6 @@ typedef struct Toy_Table { //32 | 64 BITNESS
|
|||||||
|
|
||||||
TOY_API Toy_Table* Toy_allocateTable();
|
TOY_API Toy_Table* Toy_allocateTable();
|
||||||
TOY_API void Toy_freeTable(Toy_Table* table);
|
TOY_API void Toy_freeTable(Toy_Table* table);
|
||||||
TOY_API void Toy_insertTable(Toy_Table** table, Toy_Value key, Toy_Value value);
|
TOY_API void Toy_insertTable(Toy_Table** tableHandle, Toy_Value key, Toy_Value value);
|
||||||
TOY_API Toy_Value Toy_lookupTable(Toy_Table** table, Toy_Value key);
|
TOY_API Toy_Value Toy_lookupTable(Toy_Table** tableHandle, Toy_Value key);
|
||||||
TOY_API void Toy_removeTable(Toy_Table** table, Toy_Value key);
|
TOY_API void Toy_removeTable(Toy_Table** tableHandle, Toy_Value key);
|
||||||
|
|||||||
@@ -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** bucketHandle) {
|
||||||
//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(bucketHandle, &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(bucketHandle, &ast, TOY_VALUE_TO_INTEGER(42));
|
||||||
Toy_private_emitAstUnary(bucket, &ast, TOY_AST_FLAG_NEGATE);
|
Toy_private_emitAstUnary(bucketHandle, &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(bucketHandle, &ast, TOY_VALUE_TO_INTEGER(42));
|
||||||
Toy_private_emitAstValue(bucket, &right, TOY_VALUE_TO_INTEGER(69));
|
Toy_private_emitAstValue(bucketHandle, &right, TOY_VALUE_TO_INTEGER(69));
|
||||||
Toy_private_emitAstBinary(bucket, &ast, TOY_AST_FLAG_ADD, right);
|
Toy_private_emitAstBinary(bucketHandle, &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(bucketHandle, &ast, TOY_VALUE_TO_INTEGER(42));
|
||||||
Toy_private_emitAstValue(bucket, &right, TOY_VALUE_TO_INTEGER(69));
|
Toy_private_emitAstValue(bucketHandle, &right, TOY_VALUE_TO_INTEGER(69));
|
||||||
Toy_private_emitAstBinary(bucket, &ast, TOY_AST_FLAG_ADD, right);
|
Toy_private_emitAstBinary(bucketHandle, &ast, TOY_AST_FLAG_ADD, right);
|
||||||
Toy_private_emitAstGroup(bucket, &ast);
|
Toy_private_emitAstGroup(bucketHandle, &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(bucketHandle, &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(bucketHandle, &ast, TOY_VALUE_TO_INTEGER(42));
|
||||||
Toy_private_emitAstValue(bucket, &right, TOY_VALUE_TO_INTEGER(69));
|
Toy_private_emitAstValue(bucketHandle, &right, TOY_VALUE_TO_INTEGER(69));
|
||||||
Toy_private_emitAstBinary(bucket, &ast, TOY_AST_FLAG_ADD, right);
|
Toy_private_emitAstBinary(bucketHandle, &ast, TOY_AST_FLAG_ADD, right);
|
||||||
Toy_private_emitAstGroup(bucket, &ast);
|
Toy_private_emitAstGroup(bucketHandle, &ast);
|
||||||
|
|
||||||
Toy_private_appendAstBlock(bucket, block, ast);
|
Toy_private_appendAstBlock(bucketHandle, block, ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
//check if it worked
|
//check if it worked
|
||||||
@@ -216,9 +216,9 @@ int main() {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
{
|
{
|
||||||
Toy_Bucket* bucket = Toy_allocateBucket(sizeof(Toy_Ast) * 32);
|
Toy_Bucket* bucketHandle = Toy_allocateBucket(sizeof(Toy_Ast) * 32);
|
||||||
res = test_type_emission(&bucket);
|
res = test_type_emission(&bucketHandle);
|
||||||
Toy_freeBucket(&bucket);
|
Toy_freeBucket(&bucketHandle);
|
||||||
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** bucketHandle) {
|
||||||
//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(bucketHandle, &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** bucketHandle) {
|
||||||
{
|
{
|
||||||
//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(bucketHandle, &parser);
|
||||||
|
|
||||||
//run
|
//run
|
||||||
Toy_Bytecode bc = Toy_compileBytecode(ast);
|
Toy_Bytecode bc = Toy_compileBytecode(ast);
|
||||||
|
|||||||
@@ -4,18 +4,18 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
//utils
|
//utils
|
||||||
Toy_Ast* makeAstFromSource(Toy_Bucket** bucket, const char* source) {
|
Toy_Ast* makeAstFromSource(Toy_Bucket** bucketHandle, const char* source) {
|
||||||
Toy_Lexer lexer;
|
Toy_Lexer lexer;
|
||||||
Toy_bindLexer(&lexer, source);
|
Toy_bindLexer(&lexer, source);
|
||||||
|
|
||||||
Toy_Parser parser;
|
Toy_Parser parser;
|
||||||
Toy_bindParser(&parser, &lexer);
|
Toy_bindParser(&parser, &lexer);
|
||||||
|
|
||||||
return Toy_scanParser(bucket, &parser);
|
return Toy_scanParser(bucketHandle, &parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
//tests
|
//tests
|
||||||
int test_simple_empty_parsers(Toy_Bucket** bucket) {
|
int test_simple_empty_parsers(Toy_Bucket** bucketHandle) {
|
||||||
//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(bucketHandle, &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(bucketHandle, &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(bucketHandle, &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** bucketHandle) {
|
||||||
//test boolean true
|
//test boolean true
|
||||||
{
|
{
|
||||||
Toy_Ast* ast = makeAstFromSource(bucket, "true;");
|
Toy_Ast* ast = makeAstFromSource(bucketHandle, "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(bucketHandle, "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(bucketHandle, "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(bucketHandle, "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(bucketHandle, "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(bucketHandle, "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** bucketHandle) {
|
||||||
//test unary boolean negation (!true)
|
//test unary boolean negation (!true)
|
||||||
{
|
{
|
||||||
Toy_Ast* ast = makeAstFromSource(bucket, "!true;");
|
Toy_Ast* ast = makeAstFromSource(bucketHandle, "!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(bucketHandle, "!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(bucketHandle, "-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(bucketHandle, "-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(bucketHandle, "-(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(bucketHandle, "- 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** bucketHandle) {
|
||||||
//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(bucketHandle, "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(bucketHandle, "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(bucketHandle, "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(bucketHandle, "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** bucketHandle) {
|
||||||
//test term-factor precedence
|
//test term-factor precedence
|
||||||
{
|
{
|
||||||
Toy_Ast* ast = makeAstFromSource(bucket, "1 * 2 + 3 * 4;");
|
Toy_Ast* ast = makeAstFromSource(bucketHandle, "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(bucketHandle, "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(bucketHandle, "(1 + 2) * (3 + 4);");
|
||||||
|
|
||||||
//check if it worked
|
//check if it worked
|
||||||
if (
|
if (
|
||||||
|
|||||||
@@ -10,12 +10,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** bucketHandle) {
|
||||||
//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(bucketHandle, &ast);
|
||||||
|
|
||||||
//run
|
//run
|
||||||
void* buffer = Toy_compileRoutine(ast);
|
void* buffer = Toy_compileRoutine(ast);
|
||||||
@@ -64,7 +64,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(bucketHandle, &parser);
|
||||||
|
|
||||||
//run
|
//run
|
||||||
void* buffer = Toy_compileRoutine(ast);
|
void* buffer = Toy_compileRoutine(ast);
|
||||||
@@ -113,7 +113,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(bucketHandle, &parser);
|
||||||
|
|
||||||
//run
|
//run
|
||||||
void* buffer = Toy_compileRoutine(ast);
|
void* buffer = Toy_compileRoutine(ast);
|
||||||
@@ -166,7 +166,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(bucketHandle, &parser);
|
||||||
|
|
||||||
//run
|
//run
|
||||||
void* buffer = Toy_compileRoutine(ast);
|
void* buffer = Toy_compileRoutine(ast);
|
||||||
@@ -219,7 +219,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(bucketHandle, &parser);
|
||||||
|
|
||||||
//run
|
//run
|
||||||
void* buffer = Toy_compileRoutine(ast);
|
void* buffer = Toy_compileRoutine(ast);
|
||||||
@@ -273,7 +273,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(bucketHandle, &parser);
|
||||||
|
|
||||||
//run
|
//run
|
||||||
void* buffer = Toy_compileRoutine(ast);
|
void* buffer = Toy_compileRoutine(ast);
|
||||||
@@ -321,11 +321,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** bucketHandle) {
|
||||||
// //Nothing produces a unary instruction yet
|
// //Nothing produces a unary instruction yet
|
||||||
// }
|
// }
|
||||||
|
|
||||||
int test_routine_binary(Toy_Bucket** bucket) {
|
int test_routine_binary(Toy_Bucket** bucketHandle) {
|
||||||
//produce a simple algorithm
|
//produce a simple algorithm
|
||||||
{
|
{
|
||||||
//setup
|
//setup
|
||||||
@@ -335,7 +335,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(bucketHandle, &parser);
|
||||||
|
|
||||||
//run
|
//run
|
||||||
void* buffer = Toy_compileRoutine(ast);
|
void* buffer = Toy_compileRoutine(ast);
|
||||||
@@ -401,7 +401,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(bucketHandle, &parser);
|
||||||
|
|
||||||
//run
|
//run
|
||||||
void* buffer = Toy_compileRoutine(ast);
|
void* buffer = Toy_compileRoutine(ast);
|
||||||
@@ -467,7 +467,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(bucketHandle, &parser);
|
||||||
|
|
||||||
//run
|
//run
|
||||||
void* buffer = Toy_compileRoutine(ast);
|
void* buffer = Toy_compileRoutine(ast);
|
||||||
@@ -533,7 +533,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(bucketHandle, &parser);
|
||||||
|
|
||||||
//run
|
//run
|
||||||
void* buffer = Toy_compileRoutine(ast);
|
void* buffer = Toy_compileRoutine(ast);
|
||||||
|
|||||||
@@ -9,21 +9,21 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
//utils
|
//utils
|
||||||
Toy_Bytecode makeBytecodeFromSource(Toy_Bucket** bucket, const char* source) {
|
Toy_Bytecode makeBytecodeFromSource(Toy_Bucket** bucketHandle, const char* source) {
|
||||||
Toy_Lexer lexer;
|
Toy_Lexer lexer;
|
||||||
Toy_bindLexer(&lexer, source);
|
Toy_bindLexer(&lexer, source);
|
||||||
|
|
||||||
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(bucketHandle, &parser);
|
||||||
Toy_Bytecode bc = Toy_compileBytecode(ast);
|
Toy_Bytecode bc = Toy_compileBytecode(ast);
|
||||||
|
|
||||||
return bc;
|
return bc;
|
||||||
}
|
}
|
||||||
|
|
||||||
//tests
|
//tests
|
||||||
int test_setup_and_teardown(Toy_Bucket** bucket) {
|
int test_setup_and_teardown(Toy_Bucket** bucketHandle) {
|
||||||
//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(bucketHandle, &parser);
|
||||||
|
|
||||||
Toy_Bytecode bc = Toy_compileBytecode(ast);
|
Toy_Bytecode bc = Toy_compileBytecode(ast);
|
||||||
|
|
||||||
@@ -73,7 +73,7 @@ int test_setup_and_teardown(Toy_Bucket** bucket) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int test_simple_execution(Toy_Bucket** bucket) {
|
int test_simple_execution(Toy_Bucket** bucketHandle) {
|
||||||
//test execution
|
//test execution
|
||||||
{
|
{
|
||||||
//generate bytecode for testing
|
//generate bytecode for testing
|
||||||
@@ -85,7 +85,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(bucketHandle, &parser);
|
||||||
|
|
||||||
Toy_Bytecode bc = Toy_compileBytecode(ast);
|
Toy_Bytecode bc = Toy_compileBytecode(ast);
|
||||||
|
|
||||||
@@ -117,7 +117,7 @@ int test_simple_execution(Toy_Bucket** bucket) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int test_opcode_not_equal(Toy_Bucket** bucket) {
|
int test_opcode_not_equal(Toy_Bucket** bucketHandle) {
|
||||||
//testing a specific opcode; '!=' is compressed into a single word, so lets check it works
|
//testing a specific opcode; '!=' is compressed into a single word, so lets check it works
|
||||||
{
|
{
|
||||||
//generate bytecode for testing
|
//generate bytecode for testing
|
||||||
@@ -129,7 +129,7 @@ int test_opcode_not_equal(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(bucketHandle, &parser);
|
||||||
|
|
||||||
Toy_Bytecode bc = Toy_compileBytecode(ast);
|
Toy_Bytecode bc = Toy_compileBytecode(ast);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user