mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 14:54:07 +10:00
Added simple assignment, read more
I was coding earlier this week, but my brain was so foggy I ended up not knowing what I was doing. After a few days break, I've cleaned up the mess, which took hours. Changes: * Variables can be assigned * Added new value types as placeholders * Added 'compare' and 'assign' to the AST * Added duplicate opcode * Added functions to copy and free values * Max name length is 255 chars * Compound assigns are squeezed into one word To be completed: * Tests for this commit's changes * Compound assignments * Variable access
This commit is contained in:
@@ -21,6 +21,8 @@ int test_sizeof_ast_64bit() {
|
||||
TEST_SIZEOF(Toy_AstValue, 24);
|
||||
TEST_SIZEOF(Toy_AstUnary, 16);
|
||||
TEST_SIZEOF(Toy_AstBinary, 24);
|
||||
TEST_SIZEOF(Toy_AstVarAssign, 24);
|
||||
TEST_SIZEOF(Toy_AstCompare, 24);
|
||||
TEST_SIZEOF(Toy_AstGroup, 16);
|
||||
TEST_SIZEOF(Toy_AstPrint, 16);
|
||||
TEST_SIZEOF(Toy_AstPass, 4);
|
||||
@@ -50,6 +52,8 @@ int test_sizeof_ast_32bit() {
|
||||
TEST_SIZEOF(Toy_AstValue, 12);
|
||||
TEST_SIZEOF(Toy_AstUnary, 12);
|
||||
TEST_SIZEOF(Toy_AstBinary, 16);
|
||||
TEST_SIZEOF(Toy_AstVarAssign, 16);
|
||||
TEST_SIZEOF(Toy_AstCompare, 16);
|
||||
TEST_SIZEOF(Toy_AstGroup, 8);
|
||||
TEST_SIZEOF(Toy_AstPrint, 8);
|
||||
TEST_SIZEOF(Toy_AstPass, 4);
|
||||
@@ -124,6 +128,56 @@ int test_type_emission(Toy_Bucket** bucketHandle) {
|
||||
}
|
||||
}
|
||||
|
||||
//emit assign
|
||||
{
|
||||
//build the AST
|
||||
Toy_Ast* ast = NULL;
|
||||
Toy_Ast* right = NULL;
|
||||
Toy_String* name = Toy_createNameStringLength(bucketHandle, "foobar", 6, TOY_VALUE_INTEGER);
|
||||
Toy_private_emitAstValue(bucketHandle, &right, TOY_VALUE_FROM_INTEGER(69));
|
||||
Toy_private_emitAstVariableAssignment(bucketHandle, &ast, name, TOY_AST_FLAG_ASSIGN, right);
|
||||
|
||||
//check if it worked
|
||||
if (
|
||||
ast == NULL ||
|
||||
ast->type != TOY_AST_VAR_ASSIGN ||
|
||||
ast->varAssign.flag != TOY_AST_FLAG_ASSIGN ||
|
||||
ast->varAssign.name == NULL ||
|
||||
ast->varAssign.name->type != TOY_STRING_NAME ||
|
||||
strcmp(ast->varAssign.name->as.name.data, "foobar") != 0 ||
|
||||
ast->varAssign.name->as.name.type != TOY_VALUE_INTEGER ||
|
||||
ast->varAssign.expr->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_AS_INTEGER(ast->varAssign.expr->value.value) != 69)
|
||||
{
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to emit an assign as 'Toy_Ast', state unknown\n" TOY_CC_RESET);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//emit compare
|
||||
{
|
||||
//build the AST
|
||||
Toy_Ast* ast = NULL;
|
||||
Toy_Ast* right = NULL;
|
||||
Toy_private_emitAstValue(bucketHandle, &ast, TOY_VALUE_FROM_INTEGER(42)); //technically, not a valid value
|
||||
Toy_private_emitAstValue(bucketHandle, &right, TOY_VALUE_FROM_INTEGER(69));
|
||||
Toy_private_emitAstCompare(bucketHandle, &ast, TOY_AST_FLAG_ADD, right);
|
||||
|
||||
//check if it worked
|
||||
if (
|
||||
ast == NULL ||
|
||||
ast->type != TOY_AST_COMPARE ||
|
||||
ast->compare.flag != TOY_AST_FLAG_ADD ||
|
||||
ast->compare.left->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_AS_INTEGER(ast->compare.left->value.value) != 42 ||
|
||||
ast->compare.right->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_AS_INTEGER(ast->compare.right->value.value) != 69)
|
||||
{
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to emit a compare as 'Toy_Ast', state unknown\n" TOY_CC_RESET);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//emit group
|
||||
{
|
||||
//build the AST
|
||||
|
||||
@@ -122,7 +122,7 @@ int test_bytecode_from_source(Toy_Bucket** bucketHandle) {
|
||||
*(int*)(offset + bc.ptr + 36) != 2 ||
|
||||
|
||||
*((unsigned char*)(offset + bc.ptr + 40)) != TOY_OPCODE_ADD ||
|
||||
*((unsigned char*)(offset + bc.ptr + 41)) != 0 ||
|
||||
*((unsigned char*)(offset + bc.ptr + 41)) != TOY_OPCODE_PASS ||
|
||||
*((unsigned char*)(offset + bc.ptr + 42)) != 0 ||
|
||||
*((unsigned char*)(offset + bc.ptr + 43)) != 0 ||
|
||||
|
||||
@@ -140,13 +140,13 @@ int test_bytecode_from_source(Toy_Bucket** bucketHandle) {
|
||||
*(int*)(offset + bc.ptr + 56) != 4 ||
|
||||
|
||||
*((unsigned char*)(offset + bc.ptr + 60)) != TOY_OPCODE_ADD ||
|
||||
*((unsigned char*)(offset + bc.ptr + 61)) != 0 ||
|
||||
*((unsigned char*)(offset + bc.ptr + 61)) != TOY_OPCODE_PASS ||
|
||||
*((unsigned char*)(offset + bc.ptr + 62)) != 0 ||
|
||||
*((unsigned char*)(offset + bc.ptr + 63)) != 0 ||
|
||||
|
||||
//multiply the two values
|
||||
*((unsigned char*)(offset + bc.ptr + 64)) != TOY_OPCODE_MULTIPLY ||
|
||||
*((unsigned char*)(offset + bc.ptr + 65)) != 0 ||
|
||||
*((unsigned char*)(offset + bc.ptr + 65)) != TOY_OPCODE_PASS ||
|
||||
*((unsigned char*)(offset + bc.ptr + 66)) != 0 ||
|
||||
*((unsigned char*)(offset + bc.ptr + 67)) != 0 ||
|
||||
|
||||
|
||||
@@ -100,6 +100,100 @@ int test_simple_empty_parsers(Toy_Bucket** bucketHandle) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_var_declare(Toy_Bucket** bucketHandle) {
|
||||
//declare with an initial value
|
||||
{
|
||||
const char* source = "var answer = 42;";
|
||||
Toy_Ast* ast = makeAstFromSource(bucketHandle, source);
|
||||
|
||||
//check if it worked
|
||||
if (
|
||||
ast == NULL ||
|
||||
ast->type != TOY_AST_BLOCK ||
|
||||
ast->block.child == NULL ||
|
||||
ast->block.child->type != TOY_AST_VAR_DECLARE ||
|
||||
|
||||
ast->block.child->varDeclare.name == NULL ||
|
||||
ast->block.child->varDeclare.name->type != TOY_STRING_NAME ||
|
||||
strcmp(ast->block.child->varDeclare.name->as.name.data, "answer") != 0 ||
|
||||
|
||||
ast->block.child->varDeclare.expr == NULL ||
|
||||
ast->block.child->varDeclare.expr->type != TOY_AST_VALUE ||
|
||||
|
||||
TOY_VALUE_IS_INTEGER(ast->block.child->varDeclare.expr->value.value) == false ||
|
||||
TOY_VALUE_AS_INTEGER(ast->block.child->varDeclare.expr->value.value) != 42)
|
||||
{
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Declare AST failed, source: %s\n" TOY_CC_RESET, source);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//declare without an initial value
|
||||
{
|
||||
const char* source = "var empty;";
|
||||
Toy_Ast* ast = makeAstFromSource(bucketHandle, source);
|
||||
|
||||
//check if it worked
|
||||
if (
|
||||
ast == NULL ||
|
||||
ast->type != TOY_AST_BLOCK ||
|
||||
ast->block.child == NULL ||
|
||||
ast->block.child->type != TOY_AST_VAR_DECLARE ||
|
||||
|
||||
ast->block.child->varDeclare.name == NULL ||
|
||||
ast->block.child->varDeclare.name->type != TOY_STRING_NAME ||
|
||||
strcmp(ast->block.child->varDeclare.name->as.name.data, "empty") != 0 ||
|
||||
|
||||
ast->block.child->varDeclare.expr == NULL ||
|
||||
ast->block.child->varDeclare.expr->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_NULL(ast->block.child->varDeclare.expr->value.value) == false ||
|
||||
|
||||
false)
|
||||
{
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Declare AST failed, source: %s\n" TOY_CC_RESET, source);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_var_assign(Toy_Bucket** bucketHandle) {
|
||||
//macro templates
|
||||
#define TEST_VAR_ASSIGN(ARG_SOURCE, ARG_FLAG, ARG_NAME, ARG_VALUE) \
|
||||
{ \
|
||||
const char* source = ARG_SOURCE; \
|
||||
Toy_Ast* ast = makeAstFromSource(bucketHandle, source); \
|
||||
if ( \
|
||||
ast == NULL || \
|
||||
ast->type != TOY_AST_BLOCK || \
|
||||
ast->block.child == NULL || \
|
||||
ast->block.child->type != TOY_AST_VAR_ASSIGN || \
|
||||
ast->block.child->varAssign.flag != ARG_FLAG || \
|
||||
ast->block.child->varAssign.name == NULL || \
|
||||
ast->block.child->varAssign.name->type != TOY_STRING_NAME || \
|
||||
strcmp(ast->block.child->varAssign.name->as.name.data, ARG_NAME) != 0 || \
|
||||
ast->block.child->varAssign.expr == NULL || \
|
||||
ast->block.child->varAssign.expr->type != TOY_AST_VALUE || \
|
||||
TOY_VALUE_IS_INTEGER(ast->block.child->varAssign.expr->value.value) == false || \
|
||||
TOY_VALUE_AS_INTEGER(ast->block.child->varAssign.expr->value.value) != ARG_VALUE) \
|
||||
{ \
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Assign AST failed, source: %s\n" TOY_CC_RESET, source); \
|
||||
return -1; \
|
||||
} \
|
||||
}
|
||||
|
||||
//run tests
|
||||
TEST_VAR_ASSIGN("answer = 42;", TOY_AST_FLAG_ASSIGN, "answer", 42);
|
||||
TEST_VAR_ASSIGN("answer += 42;", TOY_AST_FLAG_ADD_ASSIGN, "answer", 42);
|
||||
TEST_VAR_ASSIGN("answer -= 42;", TOY_AST_FLAG_SUBTRACT_ASSIGN, "answer", 42);
|
||||
TEST_VAR_ASSIGN("answer *= 42;", TOY_AST_FLAG_MULTIPLY_ASSIGN, "answer", 42);
|
||||
TEST_VAR_ASSIGN("answer /= 42;", TOY_AST_FLAG_DIVIDE_ASSIGN, "answer", 42);
|
||||
TEST_VAR_ASSIGN("answer %= 42;", TOY_AST_FLAG_MODULO_ASSIGN, "answer", 42);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_values(Toy_Bucket** bucketHandle) {
|
||||
//test boolean true
|
||||
{
|
||||
@@ -358,60 +452,6 @@ int test_binary(Toy_Bucket** bucketHandle) {
|
||||
}
|
||||
}
|
||||
|
||||
//test binary assign (using numbers for now, as identifiers aren't coded yet)
|
||||
{
|
||||
Toy_Ast* ast = makeAstFromSource(bucketHandle, "1 = 2;");
|
||||
|
||||
//check if it worked
|
||||
if (
|
||||
ast == NULL ||
|
||||
ast->type != TOY_AST_BLOCK ||
|
||||
ast->block.child == NULL ||
|
||||
ast->block.child->type != TOY_AST_BINARY ||
|
||||
ast->block.child->binary.flag != TOY_AST_FLAG_ASSIGN ||
|
||||
|
||||
ast->block.child->binary.left == NULL ||
|
||||
ast->block.child->binary.left->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_INTEGER(ast->block.child->binary.left->value.value) == false ||
|
||||
TOY_VALUE_AS_INTEGER(ast->block.child->binary.left->value.value) != 1 ||
|
||||
|
||||
ast->block.child->binary.right == NULL ||
|
||||
ast->block.child->binary.right->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_INTEGER(ast->block.child->binary.right->value.value) == false ||
|
||||
TOY_VALUE_AS_INTEGER(ast->block.child->binary.right->value.value) != 2)
|
||||
{
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to run the parser with binary assign '1 = 2'\n" TOY_CC_RESET);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//test binary compare (equality)
|
||||
{
|
||||
Toy_Ast* ast = makeAstFromSource(bucketHandle, "42 == 69;");
|
||||
|
||||
//check if it worked
|
||||
if (
|
||||
ast == NULL ||
|
||||
ast->type != TOY_AST_BLOCK ||
|
||||
ast->block.child == NULL ||
|
||||
ast->block.child->type != TOY_AST_BINARY ||
|
||||
ast->block.child->binary.flag != TOY_AST_FLAG_COMPARE_EQUAL ||
|
||||
|
||||
ast->block.child->binary.left == NULL ||
|
||||
ast->block.child->binary.left->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_INTEGER(ast->block.child->binary.left->value.value) == false ||
|
||||
TOY_VALUE_AS_INTEGER(ast->block.child->binary.left->value.value) != 42 ||
|
||||
|
||||
ast->block.child->binary.right == NULL ||
|
||||
ast->block.child->binary.right->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_INTEGER(ast->block.child->binary.right->value.value) == false ||
|
||||
TOY_VALUE_AS_INTEGER(ast->block.child->binary.right->value.value) != 69)
|
||||
{
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to run the parser with binary compare '42 == 69'\n" TOY_CC_RESET);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -574,15 +614,17 @@ int main() {
|
||||
total += res;
|
||||
}
|
||||
|
||||
// { //TODO: test_parser.c: test_var_declare()
|
||||
// Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||
// res = test_var_declare(&bucket);
|
||||
// Toy_freeBucket(&bucket);
|
||||
// if (res == 0) {
|
||||
// printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||
// }
|
||||
// total += res;
|
||||
// }
|
||||
{
|
||||
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||
res = test_var_declare(&bucket);
|
||||
Toy_freeBucket(&bucket);
|
||||
if (res == 0) {
|
||||
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||
}
|
||||
total += res;
|
||||
}
|
||||
|
||||
//TODO: assign & compare?
|
||||
|
||||
{
|
||||
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||
|
||||
@@ -364,7 +364,7 @@ int test_routine_expressions(Toy_Bucket** bucketHandle) {
|
||||
//code start
|
||||
*((unsigned char*)(code + 0)) != TOY_OPCODE_READ ||
|
||||
*((unsigned char*)(code + 1)) != TOY_VALUE_STRING ||
|
||||
*((unsigned char*)(code + 2)) != 0 ||
|
||||
*((unsigned char*)(code + 2)) != TOY_STRING_LEAF ||
|
||||
*((unsigned char*)(code + 3)) != 0 ||
|
||||
*(unsigned int*)(code + 4) != 0 || //the jump index
|
||||
*((unsigned char*)(code + 8)) != TOY_OPCODE_RETURN ||
|
||||
@@ -470,7 +470,7 @@ int test_routine_binary(Toy_Bucket** bucketHandle) {
|
||||
*(int*)(buffer + 36) != 5 ||
|
||||
|
||||
*((unsigned char*)(buffer + 40)) != TOY_OPCODE_ADD ||
|
||||
*((unsigned char*)(buffer + 41)) != 0 ||
|
||||
*((unsigned char*)(buffer + 41)) != TOY_OPCODE_PASS ||
|
||||
*((unsigned char*)(buffer + 42)) != 0 ||
|
||||
*((unsigned char*)(buffer + 43)) != 0 ||
|
||||
|
||||
@@ -670,7 +670,7 @@ int test_routine_binary(Toy_Bucket** bucketHandle) {
|
||||
*(int*)(buffer + 36) != 2 ||
|
||||
|
||||
*((unsigned char*)(buffer + 40)) != TOY_OPCODE_ADD ||
|
||||
*((unsigned char*)(buffer + 41)) != 0 ||
|
||||
*((unsigned char*)(buffer + 41)) != TOY_OPCODE_PASS ||
|
||||
*((unsigned char*)(buffer + 42)) != 0 ||
|
||||
*((unsigned char*)(buffer + 43)) != 0 ||
|
||||
|
||||
@@ -688,13 +688,13 @@ int test_routine_binary(Toy_Bucket** bucketHandle) {
|
||||
*(int*)(buffer + 56) != 4 ||
|
||||
|
||||
*((unsigned char*)(buffer + 60)) != TOY_OPCODE_ADD ||
|
||||
*((unsigned char*)(buffer + 61)) != 0 ||
|
||||
*((unsigned char*)(buffer + 61)) != TOY_OPCODE_PASS ||
|
||||
*((unsigned char*)(buffer + 62)) != 0 ||
|
||||
*((unsigned char*)(buffer + 63)) != 0 ||
|
||||
|
||||
//multiply the two values
|
||||
*((unsigned char*)(buffer + 64)) != TOY_OPCODE_MULTIPLY ||
|
||||
*((unsigned char*)(buffer + 65)) != 0 ||
|
||||
*((unsigned char*)(buffer + 65)) != TOY_OPCODE_PASS ||
|
||||
*((unsigned char*)(buffer + 66)) != 0 ||
|
||||
*((unsigned char*)(buffer + 67)) != 0 ||
|
||||
|
||||
@@ -912,7 +912,7 @@ int main() {
|
||||
total += res;
|
||||
}
|
||||
|
||||
{
|
||||
{
|
||||
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||
res = test_routine_keywords(&bucket);
|
||||
Toy_freeBucket(&bucket);
|
||||
|
||||
@@ -4,3 +4,19 @@ var answer = 42;
|
||||
//declare a variable without an initial value
|
||||
var empty;
|
||||
|
||||
//assign a previously existing variable
|
||||
answer = 6 * 9;
|
||||
|
||||
|
||||
/* TODO: implement compound assignments
|
||||
answer += 5;
|
||||
|
||||
answer -= 5;
|
||||
|
||||
answer *= 9;
|
||||
|
||||
answer /= 2;
|
||||
|
||||
answer %= 10;
|
||||
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user