Assignment target is now an AST node

This will make assigning to arbitrary targets easier.
This commit is contained in:
2024-12-04 19:24:58 +11:00
parent 62ca7a1fb7
commit 03dce296cb
7 changed files with 93 additions and 82 deletions

View File

@@ -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;
}

View File

@@ -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 {
@@ -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);

View File

@@ -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)) {
@@ -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;
}
@@ -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);
@@ -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);

View File

@@ -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, ast.name);
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;
}
//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);
}
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);
@@ -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);
@@ -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);
@@ -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);
@@ -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);
@@ -573,6 +562,8 @@ 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 {
@@ -580,21 +571,24 @@ static unsigned int writeInstructionAssign(Toy_Routine** rt, Toy_AstVarAssign as
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);

View File

@@ -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;
}

View File

@@ -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)
{
@@ -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;

View File

@@ -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 || \
@@ -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 ||
@@ -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 ||