Skip to content

Commit d521bf1

Browse files
committed
Fixed a new bug in the virtual machine, where initialization ended up outside of methods by not being separate from variable declaration.
1 parent b9784cd commit d521bf1

File tree

1 file changed

+77
-66
lines changed

1 file changed

+77
-66
lines changed

Source/DFPSR/implementation/machine/VirtualMachine.h

Lines changed: 77 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -609,7 +609,7 @@ struct VirtualMachine {
609609
// Create local variables and commands.
610610
for (int32_t c = 0; c < unresolvedMethod.commands.length(); c++) {
611611
const UnresolvedCommand &unresolvedCommand = unresolvedMethod.commands[c];
612-
this->generateLabelsAndStatements(methodIndex, initMethodIndex, unresolvedProgram, unresolvedMethod, unresolvedCommand.command, unresolvedCommand.arguments, global);
612+
this->generateMachineCode(methodIndex, initMethodIndex, unresolvedProgram, unresolvedMethod, unresolvedCommand.command, unresolvedCommand.arguments, global);
613613
}
614614
this->addReturnInstruction(methodIndex);
615615
#ifdef VIRTUAL_MACHINE_DEBUG_PRINT
@@ -898,81 +898,89 @@ struct VirtualMachine {
898898
throwError(message);
899899
}
900900

901-
// TODO: Inline into declareVariable
902-
Variable<TYPE_COUNT>* declareVariable_aux(const VMTypeDef<TYPE_COUNT>& typeDef, int32_t methodIndex, AccessType access, const ReadableString& name, bool initialize, const ReadableString& defaultValueText, bool global) {
903-
// Make commonly used data more readable
904-
Method<TYPE_COUNT>* currentMethod = &this->methods[methodIndex];
905-
906-
// Assert correctness
907-
if (global && (access == AccessType::Input || access == AccessType::Output)) {
908-
throwError(U"Cannot declare inputs or outputs globally!\n");
909-
}
910-
911-
// Count how many variables the method has of each type
912-
currentMethod->count[typeDef.dataType]++;
913-
this->methods[methodIndex].unifiedLocalIndices[typeDef.dataType].push(this->methods[methodIndex].locals.length());
914-
// Count inputs for calling the method
915-
if (access == AccessType::Input) {
916-
if (this->methods[methodIndex].declaredNonInput) {
917-
throwError(U"Cannot declare input \"", name, U"\" after a non-input has been declared. Declare inputs, outputs and locals in order.\n");
918-
}
919-
this->methods[methodIndex].inputCount++;
920-
} else if (access == AccessType::Output) {
921-
if (this->methods[methodIndex].declaredLocals) {
922-
throwError(U"Cannot declare output \"", name, U"\" after a local has been declared. Declare inputs, outputs and locals in order.\n");
923-
}
924-
this->methods[methodIndex].outputCount++;
925-
this->methods[methodIndex].declaredNonInput = true;
926-
} else if (access == AccessType::Hidden) {
927-
this->methods[methodIndex].declaredLocals = true;
928-
this->methods[methodIndex].declaredNonInput = true;
929-
}
930-
// Declare the variable so that code may find the type and index by name
931-
int32_t typeLocalIndex = currentMethod->count[typeDef.dataType] - 1;
932-
int32_t globalIndex = typeLocalToGlobalIndex(global, typeLocalIndex);
933-
this->methods[methodIndex].locals.pushConstruct(name, access, &typeDef, typeLocalIndex, global);
934-
// If the variable is supposed to be initialized automatically and no value will be given from an input, then we have to initialize it using hidden machine instructions.
935-
if (initialize && access != AccessType::Input) {
936-
// TODO: Give custom error messages when load or reset was not implemented.
937-
// If reset is missing, then the type does not have a default constructor and must have one specified.
938-
// If move is missing, then the type does not have a constructor accepting immediate constants.
939-
if (string_length(defaultValueText) > 0) {
940-
// An initial value was provided explicitly.
941-
// Look for a load instruction.
942-
this->interpretCommand(methodIndex, U"Move", List<VMA>(
943-
VMA(ArgumentType::Reference, typeDef.dataType, globalIndex),
944-
this->interpretImmediateArgument(this->memory.getReference(), defaultValueText)
945-
));
946-
} else {
947-
// No initial value was provided.
948-
// Look for a reset instruction.
949-
this->interpretCommand(methodIndex, U"Reset", List<VMA>(
950-
VMA(ArgumentType::Reference, typeDef.dataType, globalIndex)
951-
));
952-
}
953-
}
954-
return &this->methods[methodIndex].locals.last();
955-
}
956-
957901
Variable<TYPE_COUNT>* declareVariable(int32_t methodIndex, int32_t initMethodIndex, AccessType access, const ReadableString& typeName, const ReadableString& name, bool initialize, const ReadableString& defaultValueText, bool global) {
958902
if (this->getResource(name, methodIndex, initMethodIndex)) {
959903
throwError(U"A resource named \"", name, U"\" already exists! Be aware that resource names are case insensitive.\n");
960904
return nullptr;
961905
} else {
962906
// Loop over type definitions to find a match
963907
const VMTypeDef<TYPE_COUNT>* typeDef = getMachineType(typeName);
964-
if (typeDef) {
908+
if (typeDef != nullptr) {
965909
if (string_length(defaultValueText) > 0 && !typeDef->allowDefaultValue) {
966910
throwError(U"The variable \"", name, U"\" doesn't have an immediate constructor for \"", typeName, U"\".\n");
967911
}
968-
return this->declareVariable_aux(*typeDef, methodIndex, access, name, initialize, defaultValueText, global);
912+
// Declare the variable
913+
Method<TYPE_COUNT>* currentMethod = &this->methods[methodIndex];
914+
// Assert correctness
915+
if (global && (access == AccessType::Input || access == AccessType::Output)) {
916+
throwError(U"Cannot declare inputs or outputs globally!\n");
917+
}
918+
// Count how many variables the method has of each type
919+
currentMethod->count[typeDef->dataType]++;
920+
this->methods[methodIndex].unifiedLocalIndices[typeDef->dataType].push(this->methods[methodIndex].locals.length());
921+
// Count inputs for calling the method
922+
if (access == AccessType::Input) {
923+
if (this->methods[methodIndex].declaredNonInput) {
924+
throwError(U"Cannot declare input \"", name, U"\" after a non-input has been declared. Declare inputs, outputs and locals in order.\n");
925+
}
926+
this->methods[methodIndex].inputCount++;
927+
} else if (access == AccessType::Output) {
928+
if (this->methods[methodIndex].declaredLocals) {
929+
throwError(U"Cannot declare output \"", name, U"\" after a local has been declared. Declare inputs, outputs and locals in order.\n");
930+
}
931+
this->methods[methodIndex].outputCount++;
932+
this->methods[methodIndex].declaredNonInput = true;
933+
} else if (access == AccessType::Hidden) {
934+
this->methods[methodIndex].declaredLocals = true;
935+
this->methods[methodIndex].declaredNonInput = true;
936+
}
937+
// Declare the variable so that code may find the type and index by name
938+
int32_t typeLocalIndex = currentMethod->count[typeDef->dataType] - 1;
939+
int32_t globalIndex = typeLocalToGlobalIndex(global, typeLocalIndex);
940+
this->methods[methodIndex].locals.pushConstruct(name, access, typeDef, typeLocalIndex, global);
941+
return &this->methods[methodIndex].locals.last();
969942
} else {
970943
throwError(U"Cannot declare variable of unknown type \"", typeName, U"\"!\n");
971944
return nullptr;
972945
}
973946
}
974947
}
975948

949+
void initializeVariable(int32_t methodIndex, int32_t initMethodIndex, AccessType access, const ReadableString& typeName, const ReadableString& name, bool initialize, const ReadableString& defaultValueText, bool global) {
950+
const VMTypeDef<TYPE_COUNT>* typeDef = getMachineType(typeName);
951+
Method<TYPE_COUNT>* currentMethod = &this->methods[methodIndex];
952+
Variable<TYPE_COUNT>* variableDef = this->getResource(name, methodIndex, initMethodIndex);
953+
if (typeDef == nullptr) {
954+
throwError(U"Failed to find type ", typeName, U" when trying to generate machine code for initilizing ", name, U" in the virtual machine!\n");
955+
} else if (variableDef == nullptr) {
956+
throwError(U"Failed to find variable ", name, U" when trying to generate machine code for initilizing ", name, U" in the virtual machine!\n");
957+
} else {
958+
int32_t typeLocalIndex = currentMethod->count[typeDef->dataType] - 1;
959+
int32_t globalIndex = typeLocalToGlobalIndex(global, typeLocalIndex);
960+
this->methods[methodIndex].locals.pushConstruct(name, access, typeDef, typeLocalIndex, global);
961+
// If the variable is supposed to be initialized automatically and no value will be given from an input, then we have to initialize it using hidden machine instructions.
962+
if (initialize && access != AccessType::Input) {
963+
// TODO: Give custom error messages when load or reset was not implemented.
964+
// If reset is missing, then the type does not have a default constructor and must have one specified.
965+
// If move is missing, then the type does not have a constructor accepting immediate constants.
966+
if (string_length(defaultValueText) > 0) {
967+
// An initial value was provided explicitly.
968+
// Look for a load instruction.
969+
this->interpretCommand(methodIndex, U"Move", List<VMA>(
970+
VMA(ArgumentType::Reference, typeDef->dataType, globalIndex),
971+
this->interpretImmediateArgument(this->memory.getReference(), defaultValueText)
972+
));
973+
} else {
974+
// No initial value was provided.
975+
// Look for a reset instruction.
976+
this->interpretCommand(methodIndex, U"Reset", List<VMA>(
977+
VMA(ArgumentType::Reference, typeDef->dataType, globalIndex)
978+
));
979+
}
980+
}
981+
}
982+
}
983+
976984
VMA VMAfromText(const UnresolvedProgram &unresolvedProgram, const UnresolvedMethod &unresolvedMethod, int32_t methodIndex, int32_t initMethodIndex, const ReadableString& content, bool global) {
977985
#ifdef VIRTUAL_MACHINE_DEBUG_PRINT
978986
printText(U"VMAfromText in method ", methodIndex, U" interpreting argument \"", content, U"\".\n");
@@ -1029,9 +1037,9 @@ struct VirtualMachine {
10291037
}
10301038
}
10311039

1032-
void generateLabelsAndStatements(int32_t methodIndex, int32_t initMethodIndex, const UnresolvedProgram &unresolvedProgram, const UnresolvedMethod &unresolvedMethod, const ReadableString& command, const List<String>& arguments, bool global) {
1040+
void generateMachineCode(int32_t methodIndex, int32_t initMethodIndex, const UnresolvedProgram &unresolvedProgram, const UnresolvedMethod &unresolvedMethod, const ReadableString& command, const List<String>& arguments, bool global) {
10331041
#ifdef VIRTUAL_MACHINE_DEBUG_PRINT
1034-
printText(U"generateLabelsAndStatements @", this->machineWords.length(), U" in method ", methodIndex, U" ", command, U"(");
1042+
printText(U"generateMachineCode @", this->machineWords.length(), U" in method ", methodIndex, U" ", command, U"(");
10351043
for (int32_t a = 0; a < arguments.length(); a++) {
10361044
if (a > 0) { printText(U", "); }
10371045
printText(arguments[a]);
@@ -1042,11 +1050,14 @@ struct VirtualMachine {
10421050
throwError(U"Unexpected BEGIN command found inside of method!\n");
10431051
} else if (string_caseInsensitiveMatch(command, U"End")) {
10441052
throwError(U"Unexpected END command found inside of method!\n");
1045-
} else if (string_caseInsensitiveMatch(command, U"Hidden")
1046-
|| string_caseInsensitiveMatch(command, U"Input")
1047-
|| string_caseInsensitiveMatch(command, U"Output")
1048-
|| string_caseInsensitiveMatch(command, U"Temp")) {
1049-
// Variables should already be generated.
1053+
} else if (string_caseInsensitiveMatch(command, U"Input")) {
1054+
// No initialization needed for input.
1055+
} else if (string_caseInsensitiveMatch(command, U"Output")) {
1056+
this->initializeVariable(methodIndex, initMethodIndex, AccessType::Output, getArg(arguments, 0), getArg(arguments, 1), true, getArg(arguments, 2), global);
1057+
} else if (string_caseInsensitiveMatch(command, U"Hidden")) {
1058+
this->initializeVariable(methodIndex, initMethodIndex, AccessType::Hidden, getArg(arguments, 0), getArg(arguments, 1), true, getArg(arguments, 2), global);
1059+
} else if (string_caseInsensitiveMatch(command, U"Temp")) {
1060+
// No initialization needed for temp.
10501061
} else if (string_caseInsensitiveMatch(command, U"Call")) {
10511062
#ifdef VIRTUAL_MACHINE_DEBUG_PRINT
10521063
printText(U"Generating call from method ", methodIndex, U"\n");

0 commit comments

Comments
 (0)