diff --git a/source/toy_ast.c b/source/toy_ast.c index 3b028bc..19a1544 100644 --- a/source/toy_ast.c +++ b/source/toy_ast.c @@ -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; } diff --git a/source/toy_ast.h b/source/toy_ast.h index 1b72287..0f3ad81 100644 --- a/source/toy_ast.h +++ b/source/toy_ast.h @@ -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); diff --git a/source/toy_parser.c b/source/toy_parser.c index 024d915..b87883a 100644 --- a/source/toy_parser.c +++ b/source/toy_parser.c @@ -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); diff --git a/source/toy_routine.c b/source/toy_routine.c index ebc756c..77577dd 100644 --- a/source/toy_routine.c +++ b/source/toy_routine.c @@ -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); @@ -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); diff --git a/source/toy_scope.c b/source/toy_scope.c index fda31de..e475861 100644 --- a/source/toy_scope.c +++ b/source/toy_scope.c @@ -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; } diff --git a/tests/cases/test_ast.c b/tests/cases/test_ast.c index bcc115f..348458a 100644 --- a/tests/cases/test_ast.c +++ b/tests/cases/test_ast.c @@ -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; diff --git a/tests/cases/test_parser.c b/tests/cases/test_parser.c index c7f4267..51ad1c5 100644 --- a/tests/cases/test_parser.c +++ b/tests/cases/test_parser.c @@ -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 ||