Skip to content

Commit

Permalink
Assignment target is now an AST node
Browse files Browse the repository at this point in the history
This will make assigning to arbitrary targets easier.
  • Loading branch information
Ratstail91 committed Dec 4, 2024
1 parent 62ca7a1 commit 03dce29
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 82 deletions.
8 changes: 4 additions & 4 deletions source/toy_ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -171,22 +171,22 @@ void Toy_private_emitAstVariableDeclaration(Toy_Bucket** bucketHandle, Toy_Ast**
(*astHandle) = tmp;
}

void Toy_private_emitAstVariableAssignment(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_String* name, Toy_AstFlag flag, Toy_Ast* expr) {
void Toy_private_emitAstVariableAssignment(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_AstFlag flag, Toy_Ast* expr) {
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast));

tmp->type = TOY_AST_VAR_ASSIGN;
tmp->varAssign.flag = flag;
tmp->varAssign.name = name;
tmp->varAssign.target = (*astHandle);
tmp->varAssign.expr = expr;

(*astHandle) = tmp;
}

void Toy_private_emitAstVariableAccess(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_String* name) {
void Toy_private_emitAstVariableAccess(Toy_Bucket** bucketHandle, Toy_Ast** astHandle) {
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast));

tmp->type = TOY_AST_VAR_ACCESS;
tmp->varAccess.name = name;
tmp->varAccess.child = (*astHandle);

(*astHandle) = tmp;
}
Expand Down
8 changes: 4 additions & 4 deletions source/toy_ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,13 +171,13 @@ typedef struct Toy_AstVarDeclare {
typedef struct Toy_AstVarAssign {
Toy_AstType type;
Toy_AstFlag flag;
Toy_String* name;
Toy_Ast* target;
Toy_Ast* expr;
} Toy_AstVarAssign;

typedef struct Toy_AstVarAccess {
Toy_AstType type;
Toy_String* name;
Toy_Ast* child;
} Toy_AstVarAccess;

typedef struct Toy_AstPass {
Expand Down Expand Up @@ -235,8 +235,8 @@ void Toy_private_emitAstContinue(Toy_Bucket** bucketHandle, Toy_Ast** rootHandle
void Toy_private_emitAstPrint(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);

void Toy_private_emitAstVariableDeclaration(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_String* name, Toy_Ast* expr);
void Toy_private_emitAstVariableAssignment(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_String* name, Toy_AstFlag flag, Toy_Ast* expr);
void Toy_private_emitAstVariableAccess(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_String* name);
void Toy_private_emitAstVariableAssignment(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_AstFlag flag, Toy_Ast* expr);
void Toy_private_emitAstVariableAccess(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);

void Toy_private_emitAstPass(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);
void Toy_private_emitAstError(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);
Expand Down
18 changes: 9 additions & 9 deletions source/toy_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -266,8 +266,12 @@ static Toy_ValueType readType(Toy_Parser* parser) {
}

static Toy_AstFlag nameString(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {
//emit the name string
Toy_String* name = Toy_createNameStringLength(bucketHandle, parser->previous.lexeme, parser->previous.length, TOY_VALUE_UNKNOWN, false);
Toy_Value value = TOY_VALUE_FROM_STRING(name);
Toy_private_emitAstValue(bucketHandle, rootHandle, value);

//check for an assignment
Toy_AstFlag flag = TOY_AST_FLAG_NONE;

if (match(parser, TOY_TOKEN_OPERATOR_ASSIGN)) {
Expand All @@ -289,16 +293,16 @@ static Toy_AstFlag nameString(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy
flag = TOY_AST_FLAG_MODULO_ASSIGN;
}

//assignment
//emit the assignment if found
if (flag != TOY_AST_FLAG_NONE) {
Toy_Ast* expr = NULL;
parsePrecedence(bucketHandle, parser, &expr, PREC_ASSIGNMENT); //this makes chained assignment possible, I think
Toy_private_emitAstVariableAssignment(bucketHandle, rootHandle, name, flag, expr);
Toy_private_emitAstVariableAssignment(bucketHandle, rootHandle, flag, expr);
return TOY_AST_FLAG_NONE;
}

//assume it's an access
Toy_private_emitAstVariableAccess(bucketHandle, rootHandle, name);
//assume it's an access instead
Toy_private_emitAstVariableAccess(bucketHandle, rootHandle);
return TOY_AST_FLAG_NONE;
}

Expand Down Expand Up @@ -643,9 +647,6 @@ static void parsePrecedence(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_A
return;
}

//grab this for name storage
Toy_Token prevToken = parser->previous;

Toy_Ast* ptr = NULL;
Toy_AstFlag flag = infix(bucketHandle, parser, &ptr);

Expand All @@ -656,8 +657,7 @@ static void parsePrecedence(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_A
}
//eww, gross
else if (flag >= 10 && flag <= 19) {
Toy_String* name = Toy_createNameStringLength(bucketHandle, prevToken.lexeme, prevToken.length, TOY_VALUE_UNKNOWN, false);
Toy_private_emitAstVariableAssignment(bucketHandle, rootHandle, name, flag, ptr);
Toy_private_emitAstVariableAssignment(bucketHandle, rootHandle, flag, ptr);
}
else if (flag >= 20 && flag <= 29) {
Toy_private_emitAstCompare(bucketHandle, rootHandle, flag, ptr);
Expand Down
86 changes: 40 additions & 46 deletions source/toy_routine.c
Original file line number Diff line number Diff line change
Expand Up @@ -471,27 +471,36 @@ static unsigned int writeInstructionAssign(Toy_Routine** rt, Toy_AstVarAssign as
break;
}

//name, duplicate, right, opcode
if (ast.flag == TOY_AST_FLAG_ASSIGN) {
//target, based on type
if (ast.target->type == TOY_AST_VALUE && TOY_VALUE_IS_STRING(ast.target->value.value) && TOY_VALUE_AS_STRING(ast.target->value.value)->type == TOY_STRING_NAME) {
//name string
Toy_String* target = TOY_VALUE_AS_STRING(ast.target->value.value);

//emit the name string
EMIT_BYTE(rt, code, TOY_OPCODE_READ);
EMIT_BYTE(rt, code, TOY_VALUE_STRING);
EMIT_BYTE(rt, code, TOY_STRING_NAME);
EMIT_BYTE(rt, code, ast.name->length); //store the length (max 255)
EMIT_BYTE(rt, code, target->length); //store the length (max 255)

emitString(rt, target);
}
else {
//URGENT: assigning to an array member
fprintf(stderr, TOY_CC_ERROR "COMPILER ERROR: TODO at %s %d\n" TOY_CC_RESET, __FILE__, __LINE__);
(*rt)->panic = true;
return 0;
}

emitString(rt, ast.name);
//determine RHS, include duplication if needed
if (ast.flag == TOY_AST_FLAG_ASSIGN) {
result += writeRoutineCode(rt, ast.expr);

EMIT_BYTE(rt, code, TOY_OPCODE_ASSIGN);
EMIT_BYTE(rt, code, 0);
EMIT_BYTE(rt, code,0);
EMIT_BYTE(rt, code,0);
EMIT_BYTE(rt, code,0);
}
else if (ast.flag == TOY_AST_FLAG_ADD_ASSIGN) {
EMIT_BYTE(rt, code, TOY_OPCODE_READ);
EMIT_BYTE(rt, code, TOY_VALUE_STRING);
EMIT_BYTE(rt, code, TOY_STRING_NAME);
EMIT_BYTE(rt, code, ast.name->length); //store the length (max 255)

emitString(rt, ast.name);

EMIT_BYTE(rt, code,TOY_OPCODE_DUPLICATE);
EMIT_BYTE(rt, code,TOY_OPCODE_ACCESS); //squeezed
EMIT_BYTE(rt, code,0);
Expand All @@ -501,15 +510,10 @@ static unsigned int writeInstructionAssign(Toy_Routine** rt, Toy_AstVarAssign as

EMIT_BYTE(rt, code,TOY_OPCODE_ADD);
EMIT_BYTE(rt, code,TOY_OPCODE_ASSIGN); //squeezed
EMIT_BYTE(rt, code,0);
EMIT_BYTE(rt, code,0);
}
else if (ast.flag == TOY_AST_FLAG_SUBTRACT_ASSIGN) {
EMIT_BYTE(rt, code, TOY_OPCODE_READ);
EMIT_BYTE(rt, code, TOY_VALUE_STRING);
EMIT_BYTE(rt, code, TOY_STRING_NAME);
EMIT_BYTE(rt, code, ast.name->length); //store the length (max 255)

emitString(rt, ast.name);

EMIT_BYTE(rt, code,TOY_OPCODE_DUPLICATE);
EMIT_BYTE(rt, code,TOY_OPCODE_ACCESS); //squeezed
EMIT_BYTE(rt, code,0);
Expand All @@ -519,15 +523,10 @@ static unsigned int writeInstructionAssign(Toy_Routine** rt, Toy_AstVarAssign as

EMIT_BYTE(rt, code,TOY_OPCODE_SUBTRACT);
EMIT_BYTE(rt, code,TOY_OPCODE_ASSIGN); //squeezed
EMIT_BYTE(rt, code,0);
EMIT_BYTE(rt, code,0);
}
else if (ast.flag == TOY_AST_FLAG_MULTIPLY_ASSIGN) {
EMIT_BYTE(rt, code, TOY_OPCODE_READ);
EMIT_BYTE(rt, code, TOY_VALUE_STRING);
EMIT_BYTE(rt, code, TOY_STRING_NAME);
EMIT_BYTE(rt, code, ast.name->length); //store the length (max 255)

emitString(rt, ast.name);

EMIT_BYTE(rt, code,TOY_OPCODE_DUPLICATE);
EMIT_BYTE(rt, code,TOY_OPCODE_ACCESS); //squeezed
EMIT_BYTE(rt, code,0);
Expand All @@ -537,15 +536,10 @@ static unsigned int writeInstructionAssign(Toy_Routine** rt, Toy_AstVarAssign as

EMIT_BYTE(rt, code,TOY_OPCODE_MULTIPLY);
EMIT_BYTE(rt, code,TOY_OPCODE_ASSIGN); //squeezed
EMIT_BYTE(rt, code,0);
EMIT_BYTE(rt, code,0);
}
else if (ast.flag == TOY_AST_FLAG_DIVIDE_ASSIGN) {
EMIT_BYTE(rt, code, TOY_OPCODE_READ);
EMIT_BYTE(rt, code, TOY_VALUE_STRING);
EMIT_BYTE(rt, code, TOY_STRING_NAME);
EMIT_BYTE(rt, code, ast.name->length); //store the length (max 255)

emitString(rt, ast.name);

EMIT_BYTE(rt, code,TOY_OPCODE_DUPLICATE);
EMIT_BYTE(rt, code,TOY_OPCODE_ACCESS); //squeezed
EMIT_BYTE(rt, code,0);
Expand All @@ -555,15 +549,10 @@ static unsigned int writeInstructionAssign(Toy_Routine** rt, Toy_AstVarAssign as

EMIT_BYTE(rt, code,TOY_OPCODE_DIVIDE);
EMIT_BYTE(rt, code,TOY_OPCODE_ASSIGN); //squeezed
EMIT_BYTE(rt, code,0);
EMIT_BYTE(rt, code,0);
}
else if (ast.flag == TOY_AST_FLAG_MODULO_ASSIGN) {
EMIT_BYTE(rt, code, TOY_OPCODE_READ);
EMIT_BYTE(rt, code, TOY_VALUE_STRING);
EMIT_BYTE(rt, code, TOY_STRING_NAME);
EMIT_BYTE(rt, code, ast.name->length); //store the length (max 255)

emitString(rt, ast.name);

EMIT_BYTE(rt, code,TOY_OPCODE_DUPLICATE);
EMIT_BYTE(rt, code,TOY_OPCODE_ACCESS); //squeezed
EMIT_BYTE(rt, code,0);
Expand All @@ -573,28 +562,33 @@ static unsigned int writeInstructionAssign(Toy_Routine** rt, Toy_AstVarAssign as

EMIT_BYTE(rt, code,TOY_OPCODE_MODULO);
EMIT_BYTE(rt, code,TOY_OPCODE_ASSIGN); //squeezed
EMIT_BYTE(rt, code,0);
EMIT_BYTE(rt, code,0);
}

else {
fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid AST assign flag found\n" TOY_CC_RESET);
exit(-1);
}

//4-byte alignment
EMIT_BYTE(rt, code,0);
EMIT_BYTE(rt, code,0);

return result;
}

static unsigned int writeInstructionAccess(Toy_Routine** rt, Toy_AstVarAccess ast) {
if (!(ast.child->type == TOY_AST_VALUE && TOY_VALUE_IS_STRING(ast.child->value.value) && TOY_VALUE_AS_STRING(ast.child->value.value)->type == TOY_STRING_NAME)) {
fprintf(stderr, TOY_CC_ERROR "COMPILER ERROR: Found a non-name-string in a value node when trying to write access\n" TOY_CC_RESET);
exit(-1);
}

Toy_String* name = TOY_VALUE_AS_STRING(ast.child->value.value);

//push the name
EMIT_BYTE(rt, code, TOY_OPCODE_READ);
EMIT_BYTE(rt, code, TOY_VALUE_STRING);
EMIT_BYTE(rt, code, TOY_STRING_NAME);
EMIT_BYTE(rt, code, ast.name->length); //store the length (max 255)
EMIT_BYTE(rt, code, name->length); //store the length (max 255)

emitString(rt, ast.name);
emitString(rt, name);

//convert name to value
EMIT_BYTE(rt, code, TOY_OPCODE_ACCESS);
Expand Down
2 changes: 1 addition & 1 deletion source/toy_scope.c
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ void Toy_assignScope(Toy_Scope* scope, Toy_String* key, Toy_Value value) {

if (entryPtr == NULL) {
char buffer[key->length + 256];
sprintf(buffer, "Undefined variable: %s", key->as.name.data);
sprintf(buffer, "Undefined variable: %s\n", key->as.name.data);
Toy_error(buffer);
return;
}
Expand Down
29 changes: 18 additions & 11 deletions tests/cases/test_ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -396,18 +396,23 @@ int test_type_emission(Toy_Bucket** bucketHandle) {
Toy_Ast* ast = NULL;
Toy_Ast* right = NULL;
Toy_String* name = Toy_createNameStringLength(bucketHandle, "foobar", 6, TOY_VALUE_INTEGER, false);
Toy_private_emitAstValue(bucketHandle, &ast, TOY_VALUE_FROM_STRING(name));
Toy_private_emitAstValue(bucketHandle, &right, TOY_VALUE_FROM_INTEGER(69));
Toy_private_emitAstVariableAssignment(bucketHandle, &ast, name, TOY_AST_FLAG_ASSIGN, right);
Toy_private_emitAstVariableAssignment(bucketHandle, &ast, 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.target == NULL ||
ast->varAssign.target->type != TOY_AST_VALUE ||
TOY_VALUE_IS_STRING(ast->varAssign.target->value.value) != true ||
TOY_VALUE_AS_STRING(ast->varAssign.target->value.value)->type != TOY_STRING_NAME ||
strcmp(TOY_VALUE_AS_STRING(ast->varAssign.target->value.value)->as.name.data, "foobar") != 0 ||

TOY_VALUE_AS_STRING(ast->varAssign.target->value.value)->as.name.type != TOY_VALUE_INTEGER ||

ast->varAssign.expr->type != TOY_AST_VALUE ||
TOY_VALUE_AS_INTEGER(ast->varAssign.expr->value.value) != 69)
{
Expand All @@ -420,18 +425,20 @@ int test_type_emission(Toy_Bucket** bucketHandle) {
{
//build the AST
Toy_Ast* ast = NULL;
Toy_Ast* right = NULL;
Toy_String* name = Toy_createNameStringLength(bucketHandle, "foobar", 6, TOY_VALUE_INTEGER, false);
Toy_private_emitAstVariableAccess(bucketHandle, &ast, name);
Toy_private_emitAstValue(bucketHandle, &ast, TOY_VALUE_FROM_STRING(name));
Toy_private_emitAstVariableAccess(bucketHandle, &ast);

//check if it worked
if (
ast == NULL ||
ast->type != TOY_AST_VAR_ACCESS ||
ast->varAccess.name == NULL ||
ast->varAccess.name->type != TOY_STRING_NAME ||
strcmp(ast->varAccess.name->as.name.data, "foobar") != 0 ||
ast->varAccess.name->as.name.type != TOY_VALUE_INTEGER)
ast->varAccess.child == NULL ||
ast->varAccess.child->type != TOY_AST_VALUE ||
TOY_VALUE_IS_STRING(ast->varAccess.child->value.value) != true ||
TOY_VALUE_AS_STRING(ast->varAccess.child->value.value)->type != TOY_STRING_NAME ||
strcmp(TOY_VALUE_AS_STRING(ast->varAccess.child->value.value)->as.name.data, "foobar") != 0 ||
TOY_VALUE_AS_STRING(ast->varAccess.child->value.value)->as.name.type != TOY_VALUE_INTEGER)
{
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to emit an access as 'Toy_Ast', state unknown\n" TOY_CC_RESET);
return -1;
Expand Down
24 changes: 17 additions & 7 deletions tests/cases/test_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,11 @@ int test_var_assign(Toy_Bucket** bucketHandle) {
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.target == NULL || \
ast->block.child->varAssign.target->type != TOY_AST_VALUE || \
TOY_VALUE_IS_STRING(ast->block.child->varAssign.target->value.value) != true ||\
TOY_VALUE_AS_STRING(ast->block.child->varAssign.target->value.value)->type != TOY_STRING_NAME ||\
strcmp(TOY_VALUE_AS_STRING(ast->block.child->varAssign.target->value.value)->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 || \
Expand Down Expand Up @@ -512,8 +514,11 @@ int test_aggregate(Toy_Bucket** bucketHandle) {

ast->block.child->aggregate.left == NULL ||
ast->block.child->aggregate.left->type != TOY_AST_VAR_ACCESS ||
ast->block.child->aggregate.left->varAccess.name->type != TOY_STRING_NAME ||
strcmp(ast->block.child->aggregate.left->varAccess.name->as.name.data, "name") != 0 ||
ast->block.child->aggregate.left->varAccess.child == NULL ||
ast->block.child->aggregate.left->varAccess.child->type != TOY_AST_VALUE ||
TOY_VALUE_IS_STRING(ast->block.child->aggregate.left->varAccess.child->value.value) != true ||
TOY_VALUE_AS_STRING(ast->block.child->aggregate.left->varAccess.child->value.value)->type != TOY_STRING_NAME ||
strcmp(TOY_VALUE_AS_STRING(ast->block.child->aggregate.left->varAccess.child->value.value)->as.name.data, "name") != 0 ||

ast->block.child->aggregate.right->type != TOY_AST_VALUE ||
TOY_VALUE_IS_INTEGER(ast->block.child->aggregate.right->value.value) != true ||
Expand Down Expand Up @@ -542,8 +547,13 @@ int test_aggregate(Toy_Bucket** bucketHandle) {

ast->block.child->aggregate.left == NULL ||
ast->block.child->aggregate.left->type != TOY_AST_VAR_ACCESS ||
ast->block.child->aggregate.left->varAccess.name->type != TOY_STRING_NAME ||
strcmp(ast->block.child->aggregate.left->varAccess.name->as.name.data, "name") != 0 ||

ast->block.child->aggregate.left->varAccess.child == NULL ||
ast->block.child->aggregate.left->varAccess.child->type != TOY_AST_VALUE ||
TOY_VALUE_IS_STRING(ast->block.child->aggregate.left->varAccess.child->value.value) != true ||
TOY_VALUE_AS_STRING(ast->block.child->aggregate.left->varAccess.child->value.value)->type != TOY_STRING_NAME ||

strcmp(TOY_VALUE_AS_STRING(ast->block.child->aggregate.left->varAccess.child->value.value)->as.name.data, "name") != 0 ||

ast->block.child->aggregate.right->type != TOY_AST_AGGREGATE ||
ast->block.child->aggregate.right->aggregate.flag != TOY_AST_FLAG_COLLECTION ||
Expand Down

0 comments on commit 03dce29

Please sign in to comment.