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,17 +1,17 @@
|
||||
#include "toy_ast.h"
|
||||
|
||||
void Toy_private_initAstBlock(Toy_Bucket** bucket, Toy_Ast** handle) {
|
||||
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucket, sizeof(Toy_Ast));
|
||||
void Toy_private_initAstBlock(Toy_Bucket** bucketHandle, Toy_Ast** astHandle) {
|
||||
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast));
|
||||
|
||||
tmp->type = TOY_AST_BLOCK;
|
||||
tmp->block.child = NULL;
|
||||
tmp->block.next = 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
|
||||
if (block->block.child == NULL) {
|
||||
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
|
||||
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
|
||||
iter->block.next->block.child = child;
|
||||
block->block.tail = iter->block.next;
|
||||
}
|
||||
|
||||
void Toy_private_emitAstValue(Toy_Bucket** bucket, Toy_Ast** handle, Toy_Value value) {
|
||||
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucket, sizeof(Toy_Ast));
|
||||
void Toy_private_emitAstValue(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_Value value) {
|
||||
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast));
|
||||
|
||||
tmp->type = TOY_AST_VALUE;
|
||||
tmp->value.value = value;
|
||||
|
||||
(*handle) = tmp;
|
||||
(*astHandle) = tmp;
|
||||
}
|
||||
|
||||
void Toy_private_emitAstUnary(Toy_Bucket** bucket, Toy_Ast** handle, Toy_AstFlag flag) {
|
||||
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucket, sizeof(Toy_Ast));
|
||||
void Toy_private_emitAstUnary(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_AstFlag flag) {
|
||||
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast));
|
||||
|
||||
tmp->type = TOY_AST_UNARY;
|
||||
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) {
|
||||
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucket, sizeof(Toy_Ast));
|
||||
void Toy_private_emitAstBinary(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_AstFlag flag, Toy_Ast* right) {
|
||||
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast));
|
||||
|
||||
tmp->type = TOY_AST_BINARY;
|
||||
tmp->binary.flag = flag;
|
||||
tmp->binary.left = *handle; //left-recursive
|
||||
tmp->binary.left = *astHandle; //left-recursive
|
||||
tmp->binary.right = right;
|
||||
|
||||
(*handle) = tmp;
|
||||
(*astHandle) = tmp;
|
||||
}
|
||||
|
||||
void Toy_private_emitAstGroup(Toy_Bucket** bucket, Toy_Ast** handle) {
|
||||
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucket, sizeof(Toy_Ast));
|
||||
void Toy_private_emitAstGroup(Toy_Bucket** bucketHandle, Toy_Ast** astHandle) {
|
||||
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast));
|
||||
|
||||
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) {
|
||||
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucket, sizeof(Toy_Ast));
|
||||
void Toy_private_emitAstPass(Toy_Bucket** bucketHandle, Toy_Ast** astHandle) {
|
||||
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast));
|
||||
|
||||
tmp->type = TOY_AST_PASS;
|
||||
|
||||
(*handle) = tmp;
|
||||
(*astHandle) = tmp;
|
||||
}
|
||||
|
||||
void Toy_private_emitAstError(Toy_Bucket** bucket, Toy_Ast** handle) {
|
||||
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucket, sizeof(Toy_Ast));
|
||||
void Toy_private_emitAstError(Toy_Bucket** bucketHandle, Toy_Ast** astHandle) {
|
||||
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast));
|
||||
|
||||
tmp->type = TOY_AST_ERROR;
|
||||
|
||||
(*handle) = tmp;
|
||||
(*astHandle) = tmp;
|
||||
}
|
||||
|
||||
void Toy_private_emitAstEnd(Toy_Bucket** bucket, Toy_Ast** handle) {
|
||||
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucket, sizeof(Toy_Ast));
|
||||
void Toy_private_emitAstEnd(Toy_Bucket** bucketHandle, Toy_Ast** astHandle) {
|
||||
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast));
|
||||
|
||||
tmp->type = TOY_AST_END;
|
||||
|
||||
(*handle) = tmp;
|
||||
(*astHandle) = tmp;
|
||||
}
|
||||
|
||||
@@ -110,14 +110,14 @@ union Toy_Ast { //32 | 64 BITNESS
|
||||
Toy_AstEnd end; //4 | 4
|
||||
}; //16 | 32
|
||||
|
||||
void Toy_private_initAstBlock(Toy_Bucket** bucket, Toy_Ast** handle);
|
||||
void Toy_private_appendAstBlock(Toy_Bucket** bucket, Toy_Ast* block, Toy_Ast* child);
|
||||
void Toy_private_initAstBlock(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);
|
||||
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_emitAstUnary(Toy_Bucket** bucket, Toy_Ast** handle, Toy_AstFlag flag);
|
||||
void Toy_private_emitAstBinary(Toy_Bucket** bucket, Toy_Ast** handle,Toy_AstFlag flag, Toy_Ast* right);
|
||||
void Toy_private_emitAstGroup(Toy_Bucket** bucket, Toy_Ast** handle);
|
||||
void Toy_private_emitAstValue(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_Value value);
|
||||
void Toy_private_emitAstUnary(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_AstFlag flag);
|
||||
void Toy_private_emitAstBinary(Toy_Bucket** bucketHandle, Toy_Ast** astHandle,Toy_AstFlag flag, Toy_Ast* right);
|
||||
void Toy_private_emitAstGroup(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);
|
||||
|
||||
void Toy_private_emitAstPass(Toy_Bucket** bucket, Toy_Ast** handle);
|
||||
void Toy_private_emitAstError(Toy_Bucket** bucket, Toy_Ast** handle);
|
||||
void Toy_private_emitAstEnd(Toy_Bucket** bucket, Toy_Ast** handle);
|
||||
void Toy_private_emitAstPass(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);
|
||||
void Toy_private_emitAstError(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);
|
||||
void Toy_private_emitAstEnd(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);
|
||||
@@ -97,7 +97,7 @@ typedef enum ParsingPrecedence {
|
||||
PREC_PRIMARY,
|
||||
} 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 {
|
||||
ParsingPrecedence precedence;
|
||||
@@ -105,12 +105,12 @@ typedef struct ParsingTuple {
|
||||
ParsingRule infix;
|
||||
} 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 unary(Toy_Bucket** bucket, Toy_Parser* parser, Toy_Ast** root);
|
||||
static Toy_AstFlag binary(Toy_Bucket** bucket, Toy_Parser* parser, Toy_Ast** root);
|
||||
static Toy_AstFlag group(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** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle);
|
||||
static Toy_AstFlag binary(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle);
|
||||
static Toy_AstFlag group(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle);
|
||||
|
||||
//precedence definitions
|
||||
static ParsingTuple parsingRulesetTable[] = {
|
||||
@@ -214,18 +214,18 @@ static ParsingTuple parsingRulesetTable[] = {
|
||||
{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) {
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -258,173 +258,173 @@ static Toy_AstFlag atomic(Toy_Bucket** bucket, Toy_Parser* parser, Toy_Ast** roo
|
||||
|
||||
float value = 0;
|
||||
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;
|
||||
}
|
||||
|
||||
default:
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
//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) {
|
||||
|
||||
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
|
||||
if ((*root)->type == TOY_AST_VALUE && TOY_VALUE_IS_INTEGER((*root)->value.value) && connectedDigit) {
|
||||
(*root)->value.value = TOY_VALUE_TO_INTEGER( -TOY_VALUE_AS_INTEGER((*root)->value.value) );
|
||||
if ((*rootHandle)->type == TOY_AST_VALUE && TOY_VALUE_IS_INTEGER((*rootHandle)->value.value) && connectedDigit) {
|
||||
(*rootHandle)->value.value = TOY_VALUE_TO_INTEGER( -TOY_VALUE_AS_INTEGER((*rootHandle)->value.value) );
|
||||
}
|
||||
else if ((*root)->type == TOY_AST_VALUE && TOY_VALUE_IS_FLOAT((*root)->value.value) && connectedDigit) {
|
||||
(*root)->value.value = TOY_VALUE_TO_FLOAT( -TOY_VALUE_AS_FLOAT((*root)->value.value) );
|
||||
else if ((*rootHandle)->type == TOY_AST_VALUE && TOY_VALUE_IS_FLOAT((*rootHandle)->value.value) && connectedDigit) {
|
||||
(*rootHandle)->value.value = TOY_VALUE_TO_FLOAT( -TOY_VALUE_AS_FLOAT((*rootHandle)->value.value) );
|
||||
}
|
||||
else {
|
||||
//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) {
|
||||
parsePrecedence(bucket, parser, root, PREC_UNARY);
|
||||
parsePrecedence(bucketHandle, parser, rootHandle, PREC_UNARY);
|
||||
|
||||
//inverted booleans
|
||||
if ((*root)->type == TOY_AST_VALUE && TOY_VALUE_IS_BOOLEAN((*root)->value.value)) {
|
||||
(*root)->value.value = TOY_VALUE_TO_BOOLEAN( !TOY_VALUE_AS_BOOLEAN((*root)->value.value) );
|
||||
if ((*rootHandle)->type == TOY_AST_VALUE && TOY_VALUE_IS_BOOLEAN((*rootHandle)->value.value)) {
|
||||
(*rootHandle)->value.value = TOY_VALUE_TO_BOOLEAN( !TOY_VALUE_AS_BOOLEAN((*rootHandle)->value.value) );
|
||||
}
|
||||
else {
|
||||
//actually emit the negation node
|
||||
Toy_private_emitAstUnary(bucket, root, TOY_AST_FLAG_NEGATE);
|
||||
Toy_private_emitAstUnary(bucketHandle, rootHandle, TOY_AST_FLAG_NEGATE);
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
advance(parser);
|
||||
|
||||
switch(parser->previous.type) {
|
||||
//arithmetic
|
||||
case TOY_TOKEN_OPERATOR_ADD: {
|
||||
parsePrecedence(bucket, parser, root, PREC_TERM + 1);
|
||||
parsePrecedence(bucketHandle, parser, rootHandle, PREC_TERM + 1);
|
||||
return TOY_AST_FLAG_ADD;
|
||||
}
|
||||
|
||||
case TOY_TOKEN_OPERATOR_SUBTRACT: {
|
||||
parsePrecedence(bucket, parser, root, PREC_TERM + 1);
|
||||
parsePrecedence(bucketHandle, parser, rootHandle, PREC_TERM + 1);
|
||||
return TOY_AST_FLAG_SUBTRACT;
|
||||
}
|
||||
|
||||
case TOY_TOKEN_OPERATOR_MULTIPLY: {
|
||||
parsePrecedence(bucket, parser, root, PREC_FACTOR + 1);
|
||||
parsePrecedence(bucketHandle, parser, rootHandle, PREC_FACTOR + 1);
|
||||
return TOY_AST_FLAG_MULTIPLY;
|
||||
}
|
||||
|
||||
case TOY_TOKEN_OPERATOR_DIVIDE: {
|
||||
parsePrecedence(bucket, parser, root, PREC_FACTOR + 1);
|
||||
parsePrecedence(bucketHandle, parser, rootHandle, PREC_FACTOR + 1);
|
||||
return TOY_AST_FLAG_DIVIDE;
|
||||
}
|
||||
|
||||
case TOY_TOKEN_OPERATOR_MODULO: {
|
||||
parsePrecedence(bucket, parser, root, PREC_FACTOR + 1);
|
||||
parsePrecedence(bucketHandle, parser, rootHandle, PREC_FACTOR + 1);
|
||||
return TOY_AST_FLAG_MODULO;
|
||||
}
|
||||
|
||||
//assignment
|
||||
case TOY_TOKEN_OPERATOR_ASSIGN: {
|
||||
parsePrecedence(bucket, parser, root, PREC_ASSIGNMENT + 1);
|
||||
parsePrecedence(bucketHandle, parser, rootHandle, PREC_ASSIGNMENT + 1);
|
||||
return TOY_AST_FLAG_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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
//comparison
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
default:
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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 ()
|
||||
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");
|
||||
|
||||
//Toy_AstGroup is omitted from generation, as an optimisation
|
||||
// Toy_private_emitAstGroup(bucket, root);
|
||||
// Toy_private_emitAstGroup(bucketHandle, rootHandle);
|
||||
}
|
||||
|
||||
else {
|
||||
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;
|
||||
@@ -435,7 +435,7 @@ static ParsingTuple* getParsingRule(Toy_TokenType type) {
|
||||
}
|
||||
|
||||
//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
|
||||
advance(parser);
|
||||
|
||||
@@ -444,11 +444,11 @@ static void parsePrecedence(Toy_Bucket** bucket, Toy_Parser* parser, Toy_Ast** r
|
||||
|
||||
if (prefix == NULL) {
|
||||
printError(parser, parser->previous, "Expected expression");
|
||||
Toy_private_emitAstError(bucket, root);
|
||||
Toy_private_emitAstError(bucketHandle, rootHandle);
|
||||
return;
|
||||
}
|
||||
|
||||
prefix(bucket, parser, root);
|
||||
prefix(bucketHandle, parser, rootHandle);
|
||||
|
||||
//infix rules are left-recursive
|
||||
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) {
|
||||
printError(parser, parser->previous, "Expected operator");
|
||||
Toy_private_emitAstError(bucket, root);
|
||||
Toy_private_emitAstError(bucketHandle, rootHandle);
|
||||
return;
|
||||
}
|
||||
|
||||
Toy_Ast* ptr = NULL;
|
||||
Toy_AstFlag flag = infix(bucket, parser, &ptr);
|
||||
Toy_AstFlag flag = infix(bucketHandle, parser, &ptr);
|
||||
|
||||
//finished
|
||||
if (flag == TOY_AST_FLAG_NONE) {
|
||||
(*root) = ptr;
|
||||
(*rootHandle) = ptr;
|
||||
return;
|
||||
}
|
||||
|
||||
Toy_private_emitAstBinary(bucket, root, flag, ptr);
|
||||
Toy_private_emitAstBinary(bucketHandle, rootHandle, flag, ptr);
|
||||
}
|
||||
|
||||
//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) {
|
||||
parsePrecedence(bucket, parser, root, PREC_ASSIGNMENT);
|
||||
static void makeExpr(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {
|
||||
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
|
||||
if (match(parser, TOY_TOKEN_OPERATOR_SEMICOLON)) {
|
||||
Toy_private_emitAstPass(bucket, root);
|
||||
Toy_private_emitAstPass(bucketHandle, rootHandle);
|
||||
return;
|
||||
}
|
||||
|
||||
makeExpr(bucket, parser, root);
|
||||
makeExpr(bucketHandle, parser, rootHandle);
|
||||
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
|
||||
//print
|
||||
//assert
|
||||
@@ -506,47 +506,47 @@ static void makeStmt(Toy_Bucket** bucket, Toy_Parser* parser, Toy_Ast** root) {
|
||||
//import
|
||||
|
||||
//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
|
||||
// if (match(parser, TOY_TOKEN_KEYWORD_VAR)) {
|
||||
// makeVariableDeclarationStmt(bucket, parser, root);
|
||||
// makeVariableDeclarationStmt(bucketHandle, parser, rootHandle);
|
||||
// }
|
||||
|
||||
// //function declarations
|
||||
// else if (match(parser, TOY_TOKEN_KEYWORD_FUNCTION)) {
|
||||
// makeFunctionDeclarationStmt(bucket, parser, root);
|
||||
// makeFunctionDeclarationStmt(bucketHandle, parser, rootHandle);
|
||||
// }
|
||||
|
||||
//otherwise
|
||||
// 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
|
||||
Toy_private_initAstBlock(bucket, root);
|
||||
Toy_private_initAstBlock(bucketHandle, rootHandle);
|
||||
|
||||
//read a series of statements into the block
|
||||
while (!match(parser, TOY_TOKEN_EOF)) {
|
||||
//process the grammar rules
|
||||
Toy_Ast* stmt = NULL;
|
||||
makeDeclarationStmt(bucket, parser, &stmt);
|
||||
makeDeclarationStmt(bucketHandle, parser, &stmt);
|
||||
|
||||
//if something went wrong
|
||||
if (parser->panic) {
|
||||
synchronize(parser);
|
||||
|
||||
Toy_Ast* err = NULL;
|
||||
Toy_private_emitAstError(bucket, &err);
|
||||
Toy_private_appendAstBlock(bucket, *root, err);
|
||||
Toy_private_emitAstError(bucketHandle, &err);
|
||||
Toy_private_appendAstBlock(bucketHandle, *rootHandle, err);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
Toy_Ast* Toy_scanParser(Toy_Bucket** bucket, Toy_Parser* parser) {
|
||||
Toy_Ast* root = NULL;
|
||||
Toy_Ast* Toy_scanParser(Toy_Bucket** bucketHandle, Toy_Parser* parser) {
|
||||
Toy_Ast* rootHandle = NULL;
|
||||
|
||||
//check for EOF
|
||||
if (match(parser, TOY_TOKEN_EOF)) {
|
||||
Toy_private_emitAstEnd(bucket, &root);
|
||||
return root;
|
||||
Toy_private_emitAstEnd(bucketHandle, &rootHandle);
|
||||
return rootHandle;
|
||||
}
|
||||
|
||||
makeBlockStmt(bucket, parser, &root);
|
||||
makeBlockStmt(bucketHandle, parser, &rootHandle);
|
||||
|
||||
return root;
|
||||
return rootHandle;
|
||||
}
|
||||
|
||||
void Toy_resetParser(Toy_Parser* parser) {
|
||||
|
||||
@@ -17,5 +17,5 @@ typedef struct Toy_Parser {
|
||||
} Toy_Parser;
|
||||
|
||||
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);
|
||||
|
||||
@@ -27,60 +27,60 @@ void Toy_freeStack(Toy_Stack* 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
|
||||
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);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
//expand the capacity if needed
|
||||
if ((*stack)->count + 1 > (*stack)->capacity) {
|
||||
while ((*stack)->count + 1 > (*stack)->capacity) {
|
||||
(*stack)->capacity = (*stack)->capacity < MIN_CAPACITY ? MIN_CAPACITY : (*stack)->capacity * 2;
|
||||
if ((*stackHandle)->count + 1 > (*stackHandle)->capacity) {
|
||||
while ((*stackHandle)->count + 1 > (*stackHandle)->capacity) {
|
||||
(*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)));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
//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) {
|
||||
if ((*stack)->count == 0) {
|
||||
Toy_Value Toy_peekStack(Toy_Stack** stackHandle) {
|
||||
if ((*stackHandle)->count == 0) {
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Stack underflow\n" TOY_CC_RESET);
|
||||
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) {
|
||||
if ((*stack)->count == 0) {
|
||||
Toy_Value Toy_popStack(Toy_Stack** stackHandle) {
|
||||
if ((*stackHandle)->count == 0) {
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Stack underflow\n" TOY_CC_RESET);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
//shrink if possible
|
||||
if ((*stack)->count > MIN_CAPACITY && (*stack)->count < (*stack)->capacity / 4) {
|
||||
(*stack)->capacity /= 2;
|
||||
unsigned int newCapacity = (*stack)->capacity;
|
||||
if ((*stackHandle)->count > MIN_CAPACITY && (*stackHandle)->count < (*stackHandle)->capacity / 4) {
|
||||
(*stackHandle)->capacity /= 2;
|
||||
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)));
|
||||
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 void Toy_freeStack(Toy_Stack* stack);
|
||||
|
||||
TOY_API void Toy_pushStack(Toy_Stack** stack, Toy_Value value);
|
||||
TOY_API Toy_Value Toy_peekStack(Toy_Stack** stack);
|
||||
TOY_API Toy_Value Toy_popStack(Toy_Stack** stack);
|
||||
TOY_API void Toy_pushStack(Toy_Stack** stackHandle, Toy_Value value);
|
||||
TOY_API Toy_Value Toy_peekStack(Toy_Stack** stackHandle);
|
||||
TOY_API Toy_Value Toy_popStack(Toy_Stack** stackHandle);
|
||||
|
||||
@@ -35,14 +35,14 @@ static void decrementRefCount(Toy_String* str) {
|
||||
}
|
||||
|
||||
//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);
|
||||
|
||||
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* ret = (Toy_String*)Toy_partitionBucket(bucket, sizeof(Toy_String) + length + 1); //TODO: compensate for partitioning more space than bucket capacity
|
||||
Toy_String* Toy_createStringLength(Toy_Bucket** bucketHandle, const char* cstring, int length) {
|
||||
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->length = length;
|
||||
@@ -53,7 +53,7 @@ Toy_String* Toy_createStringLength(Toy_Bucket** bucket, const char* cstring, int
|
||||
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) {
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Can't copy a string with refcount of zero\n" TOY_CC_RESET);
|
||||
exit(-1);
|
||||
@@ -62,12 +62,12 @@ Toy_String* Toy_copyString(Toy_Bucket** bucket, Toy_String* 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) {
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Can't deep copy a string with refcount of zero\n" TOY_CC_RESET);
|
||||
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;
|
||||
@@ -79,13 +79,13 @@ Toy_String* Toy_deepCopyString(Toy_Bucket** bucket, Toy_String* str) {
|
||||
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) {
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Can't concatenate a string with refcount of zero\n" TOY_CC_RESET);
|
||||
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->length = left->length + right->length;
|
||||
|
||||
@@ -27,13 +27,13 @@ typedef struct Toy_String { //32 | 64 BITNESS
|
||||
} as; //8 | 16
|
||||
} Toy_String; //24 | 32
|
||||
|
||||
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_createString(Toy_Bucket** bucketHandle, const char* cstring);
|
||||
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_deepCopyString(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** 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);
|
||||
|
||||
|
||||
@@ -9,46 +9,46 @@
|
||||
#define MIN_CAPACITY 16
|
||||
|
||||
//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
|
||||
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 };
|
||||
|
||||
//probe
|
||||
while (true) {
|
||||
//if we're overriding an existing value
|
||||
if (TOY_VALUE_IS_EQUAL((*table)->data[probe].key, key)) {
|
||||
(*table)->data[probe] = entry;
|
||||
if (TOY_VALUE_IS_EQUAL((*tableHandle)->data[probe].key, key)) {
|
||||
(*tableHandle)->data[probe] = entry;
|
||||
|
||||
//TODO: benchmark the psl optimisation
|
||||
(*table)->minPsl = entry.psl < (*table)->minPsl ? entry.psl : (*table)->minPsl;
|
||||
(*table)->maxPsl = entry.psl > (*table)->maxPsl ? entry.psl : (*table)->maxPsl;
|
||||
(*tableHandle)->minPsl = entry.psl < (*tableHandle)->minPsl ? entry.psl : (*tableHandle)->minPsl;
|
||||
(*tableHandle)->maxPsl = entry.psl > (*tableHandle)->maxPsl ? entry.psl : (*tableHandle)->maxPsl;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//if this spot is free, insert and return
|
||||
if (TOY_VALUE_IS_NULL((*table)->data[probe].key)) {
|
||||
(*table)->data[probe] = entry;
|
||||
if (TOY_VALUE_IS_NULL((*tableHandle)->data[probe].key)) {
|
||||
(*tableHandle)->data[probe] = entry;
|
||||
|
||||
(*table)->count++;
|
||||
(*tableHandle)->count++;
|
||||
|
||||
//TODO: benchmark the psl optimisation
|
||||
(*table)->minPsl = entry.psl < (*table)->minPsl ? entry.psl : (*table)->minPsl;
|
||||
(*table)->maxPsl = entry.psl > (*table)->maxPsl ? entry.psl : (*table)->maxPsl;
|
||||
(*tableHandle)->minPsl = entry.psl < (*tableHandle)->minPsl ? entry.psl : (*tableHandle)->minPsl;
|
||||
(*tableHandle)->maxPsl = entry.psl > (*tableHandle)->maxPsl ? entry.psl : (*tableHandle)->maxPsl;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//if the new entry is "poorer", insert it and shift the old one
|
||||
if ((*table)->data[probe].psl < entry.psl) {
|
||||
Toy_TableEntry tmp = (*table)->data[probe];
|
||||
(*table)->data[probe] = entry;
|
||||
if ((*tableHandle)->data[probe].psl < entry.psl) {
|
||||
Toy_TableEntry tmp = (*tableHandle)->data[probe];
|
||||
(*tableHandle)->data[probe] = entry;
|
||||
entry = tmp;
|
||||
}
|
||||
|
||||
//adjust and continue
|
||||
probe = (probe + 1) % (*table)->capacity;
|
||||
probe = (probe + 1) % (*tableHandle)->capacity;
|
||||
entry.psl++;
|
||||
}
|
||||
}
|
||||
@@ -97,86 +97,86 @@ void Toy_freeTable(Toy_Table* 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
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Bad table key\n" TOY_CC_RESET);
|
||||
exit(-1); //TODO: #127
|
||||
}
|
||||
|
||||
//expand the capacity
|
||||
if ((*table)->count > (*table)->capacity * 0.8) {
|
||||
(*table) = adjustTableCapacity(*table, (*table)->capacity * 2);
|
||||
if ((*tableHandle)->count > (*tableHandle)->capacity * 0.8) {
|
||||
(*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
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Bad table key\n" TOY_CC_RESET);
|
||||
exit(-1); //TODO: #127
|
||||
}
|
||||
|
||||
//lookup
|
||||
unsigned int probe = Toy_hashValue(key) % (*table)->capacity;
|
||||
unsigned int probe = Toy_hashValue(key) % (*tableHandle)->capacity;
|
||||
|
||||
while (true) {
|
||||
//found the entry
|
||||
if (TOY_VALUE_IS_EQUAL((*table)->data[probe].key, key)) {
|
||||
return (*table)->data[probe].value;
|
||||
if (TOY_VALUE_IS_EQUAL((*tableHandle)->data[probe].key, key)) {
|
||||
return (*tableHandle)->data[probe].value;
|
||||
}
|
||||
|
||||
//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();
|
||||
}
|
||||
|
||||
//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
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Bad table key\n" TOY_CC_RESET);
|
||||
exit(-1); //TODO: #127
|
||||
}
|
||||
|
||||
//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
|
||||
|
||||
while (true) {
|
||||
//found the entry
|
||||
if (TOY_VALUE_IS_EQUAL((*table)->data[probe].key, key)) {
|
||||
if (TOY_VALUE_IS_EQUAL((*tableHandle)->data[probe].key, key)) {
|
||||
break;
|
||||
}
|
||||
|
||||
//if its an empty slot
|
||||
if (TOY_VALUE_IS_NULL((*table)->data[probe].key)) {
|
||||
if (TOY_VALUE_IS_NULL((*tableHandle)->data[probe].key)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//adjust and continue
|
||||
probe = (probe + 1) % (*table)->capacity;
|
||||
probe = (probe + 1) % (*tableHandle)->capacity;
|
||||
}
|
||||
|
||||
//shift along the later entries
|
||||
for (unsigned int i = (*table)->minPsl; i < (*table)->maxPsl; i++) {
|
||||
unsigned int p = (probe + i + 0) % (*table)->capacity; //prev
|
||||
unsigned int u = (probe + i + 1) % (*table)->capacity; //current
|
||||
for (unsigned int i = (*tableHandle)->minPsl; i < (*tableHandle)->maxPsl; i++) {
|
||||
unsigned int p = (probe + i + 0) % (*tableHandle)->capacity; //prev
|
||||
unsigned int u = (probe + i + 1) % (*tableHandle)->capacity; //current
|
||||
|
||||
(*table)->data[p] = (*table)->data[u];
|
||||
(*table)->data[p].psl--;
|
||||
(*tableHandle)->data[p] = (*tableHandle)->data[u];
|
||||
(*tableHandle)->data[p].psl--;
|
||||
|
||||
//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;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//finally, wipe the removed entry
|
||||
(*table)->data[wipe] = (Toy_TableEntry){ .key = TOY_VALUE_TO_NULL(), .value = TOY_VALUE_TO_NULL(), .psl = 0 };
|
||||
(*table)->count--;
|
||||
(*tableHandle)->data[wipe] = (Toy_TableEntry){ .key = TOY_VALUE_TO_NULL(), .value = TOY_VALUE_TO_NULL(), .psl = 0 };
|
||||
(*tableHandle)->count--;
|
||||
}
|
||||
@@ -22,6 +22,6 @@ typedef struct Toy_Table { //32 | 64 BITNESS
|
||||
|
||||
TOY_API Toy_Table* Toy_allocateTable();
|
||||
TOY_API void Toy_freeTable(Toy_Table* table);
|
||||
TOY_API void Toy_insertTable(Toy_Table** table, Toy_Value key, Toy_Value value);
|
||||
TOY_API Toy_Value Toy_lookupTable(Toy_Table** table, Toy_Value key);
|
||||
TOY_API void Toy_removeTable(Toy_Table** table, Toy_Value key);
|
||||
TOY_API void Toy_insertTable(Toy_Table** tableHandle, Toy_Value key, Toy_Value value);
|
||||
TOY_API Toy_Value Toy_lookupTable(Toy_Table** tableHandle, Toy_Value key);
|
||||
TOY_API void Toy_removeTable(Toy_Table** tableHandle, Toy_Value key);
|
||||
|
||||
Reference in New Issue
Block a user