mirror of
https://github.com/arabine/open-story-teller.git
synced 2025-12-06 17:09:06 +01:00
Add branch node, unit test and fixes
This commit is contained in:
parent
41914362d5
commit
9db4bae9fd
13 changed files with 878 additions and 63 deletions
|
|
@ -85,9 +85,9 @@ typedef enum
|
||||||
OP_SKIPNZ = 27, ///< skip next instruction if not zero, e.g.: skipnz r2
|
OP_SKIPNZ = 27, ///< skip next instruction if not zero, e.g.: skipnz r2
|
||||||
|
|
||||||
// Comparison
|
// Comparison
|
||||||
OP_CMP_EQ = 28, ///< compare two registers for equality, result in first e.g.: eq r4, r0, r1 (r4 = (r0 == r1 ? 1 : 0)
|
OP_CMP_EQ = 28, ///< compare two registers for equality, result in first e.g.: eq r4, r0, r1 ; similar to: r4 = (r0 == r1 ? 1 : 0
|
||||||
OP_CMP_GT = 29, ///< compare if first register is greater than the second, result in first e.g.: gt r4, r0, r1
|
OP_CMP_GT = 29, ///< compare if first register is greater than the second, result in first e.g.: gt r4, r0, r1 ; similar to: r4 = (r0 > r1 ? 1 : 0
|
||||||
OP_CMP_LT = 30, ///< compare if first register is less than the second, result in first e.g.: lt r4, r0, r1
|
OP_CMP_LT = 30, ///< compare if first register is less than the second, result in first e.g.: lt r4, r0, r1 ; similar to: r4 = (r0 < r1 ? 1 : 0
|
||||||
|
|
||||||
INSTRUCTION_COUNT
|
INSTRUCTION_COUNT
|
||||||
} chip32_instruction_t;
|
} chip32_instruction_t;
|
||||||
|
|
|
||||||
|
|
@ -462,13 +462,13 @@ private:
|
||||||
|
|
||||||
void GenerateIfFalse(std::shared_ptr<TACInstruction> instr) {
|
void GenerateIfFalse(std::shared_ptr<TACInstruction> instr) {
|
||||||
LoadOperand(instr->GetOp1(), "r0");
|
LoadOperand(instr->GetOp1(), "r0");
|
||||||
m_assembly << " skipz r0\n";
|
m_assembly << " skipnz r0\n";
|
||||||
m_assembly << " jump " << instr->GetDest()->ToString() << "\n";
|
m_assembly << " jump " << instr->GetDest()->ToString() << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenerateIfTrue(std::shared_ptr<TACInstruction> instr) {
|
void GenerateIfTrue(std::shared_ptr<TACInstruction> instr) {
|
||||||
LoadOperand(instr->GetOp1(), "r0");
|
LoadOperand(instr->GetOp1(), "r0");
|
||||||
m_assembly << " skipnz r0\n";
|
m_assembly << " skipz r0\n";
|
||||||
m_assembly << " jump " << instr->GetDest()->ToString() << "\n";
|
m_assembly << " jump " << instr->GetDest()->ToString() << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -601,8 +601,8 @@ private:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Variable::ValueType::INTEGER:
|
case Variable::ValueType::INTEGER:
|
||||||
// CORRECTION : Déclarer 1 élément, pas la valeur !
|
m_assembly << "$" << v->GetLabel() << " DV32, "
|
||||||
m_assembly << "$" << v->GetLabel() << " DV32, 1 ; "
|
<< v->GetValue<int>() << " ; "
|
||||||
<< v->GetVariableName() << "\n";
|
<< v->GetVariableName() << "\n";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -696,7 +696,13 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenerateBranchNode(std::shared_ptr<ASTNode> node) {
|
void GenerateBranchNode(std::shared_ptr<ASTNode> node) {
|
||||||
|
auto* branchNode = node->GetAs<BranchNode>();
|
||||||
|
if (!branchNode) {
|
||||||
|
throw std::runtime_error("BranchNode cast failed");
|
||||||
|
}
|
||||||
|
|
||||||
// Évaluer la condition (le BranchNode reçoit la condition sur le port 1)
|
// Évaluer la condition (le BranchNode reçoit la condition sur le port 1)
|
||||||
|
// La condition provient généralement d'un OperatorNode (comparaison)
|
||||||
auto conditionInput = node->GetDataInput(1);
|
auto conditionInput = node->GetDataInput(1);
|
||||||
if (!conditionInput) {
|
if (!conditionInput) {
|
||||||
throw std::runtime_error("BranchNode missing condition input on port 1");
|
throw std::runtime_error("BranchNode missing condition input on port 1");
|
||||||
|
|
@ -707,11 +713,12 @@ private:
|
||||||
throw std::runtime_error("BranchNode condition evaluation returned null");
|
throw std::runtime_error("BranchNode condition evaluation returned null");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Créer les labels pour true/false
|
// Créer les labels pour true/false/end
|
||||||
auto trueLabel = NewLabel("true_branch");
|
auto trueLabel = NewLabel("branch_true");
|
||||||
auto falseLabel = NewLabel("false_branch");
|
auto falseLabel = NewLabel("branch_false");
|
||||||
auto endLabel = NewLabel("end_branch");
|
auto endLabel = NewLabel("branch_end");
|
||||||
|
|
||||||
|
// Convention: 0 = false, toute autre valeur = true
|
||||||
// if (!condition) goto falseLabel
|
// if (!condition) goto falseLabel
|
||||||
auto ifInstr = std::make_shared<TACInstruction>(
|
auto ifInstr = std::make_shared<TACInstruction>(
|
||||||
TACInstruction::OpCode::IF_FALSE,
|
TACInstruction::OpCode::IF_FALSE,
|
||||||
|
|
@ -721,11 +728,11 @@ private:
|
||||||
m_program.AddInstruction(ifInstr);
|
m_program.AddInstruction(ifInstr);
|
||||||
|
|
||||||
// True branch label
|
// True branch label
|
||||||
auto labelInstr1 = std::make_shared<TACInstruction>(
|
auto labelTrue = std::make_shared<TACInstruction>(
|
||||||
TACInstruction::OpCode::LABEL,
|
TACInstruction::OpCode::LABEL,
|
||||||
trueLabel
|
trueLabel
|
||||||
);
|
);
|
||||||
m_program.AddInstruction(labelInstr1);
|
m_program.AddInstruction(labelTrue);
|
||||||
|
|
||||||
// True branch code
|
// True branch code
|
||||||
if (node->GetChild(0)) {
|
if (node->GetChild(0)) {
|
||||||
|
|
@ -740,11 +747,11 @@ private:
|
||||||
m_program.AddInstruction(gotoEnd);
|
m_program.AddInstruction(gotoEnd);
|
||||||
|
|
||||||
// False branch label
|
// False branch label
|
||||||
auto labelInstr2 = std::make_shared<TACInstruction>(
|
auto labelFalse = std::make_shared<TACInstruction>(
|
||||||
TACInstruction::OpCode::LABEL,
|
TACInstruction::OpCode::LABEL,
|
||||||
falseLabel
|
falseLabel
|
||||||
);
|
);
|
||||||
m_program.AddInstruction(labelInstr2);
|
m_program.AddInstruction(labelFalse);
|
||||||
|
|
||||||
// False branch code
|
// False branch code
|
||||||
if (node->GetChild(1)) {
|
if (node->GetChild(1)) {
|
||||||
|
|
@ -752,11 +759,11 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
// End label
|
// End label
|
||||||
auto labelInstr3 = std::make_shared<TACInstruction>(
|
auto labelEnd = std::make_shared<TACInstruction>(
|
||||||
TACInstruction::OpCode::LABEL,
|
TACInstruction::OpCode::LABEL,
|
||||||
endLabel
|
endLabel
|
||||||
);
|
);
|
||||||
m_program.AddInstruction(labelInstr3);
|
m_program.AddInstruction(labelEnd);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,16 +3,38 @@
|
||||||
#include "connection.h"
|
#include "connection.h"
|
||||||
#include "sys_lib.h"
|
#include "sys_lib.h"
|
||||||
|
|
||||||
|
|
||||||
BranchNode::BranchNode(const std::string &type)
|
BranchNode::BranchNode(const std::string &type)
|
||||||
: BaseNode(type, "Branch Node")
|
: BaseNode(type, "Branch Node")
|
||||||
{
|
{
|
||||||
|
// Configuration du nœud de branchement
|
||||||
|
SetBehavior(BaseNode::BEHAVIOR_EXECUTION);
|
||||||
|
|
||||||
|
// Port d'entrée 0: Exécution (EXECUTION_PORT)
|
||||||
|
// Port d'entrée 1: Condition (DATA_PORT)
|
||||||
|
AddInputPort(Port::EXECUTION_PORT, ">", true);
|
||||||
|
AddInputPort(Port::DATA_PORT, "condition");
|
||||||
|
|
||||||
|
// Port de sortie 0: Branche TRUE (EXECUTION_PORT)
|
||||||
|
// Port de sortie 1: Branche FALSE (EXECUTION_PORT)
|
||||||
|
AddOutputPort(Port::EXECUTION_PORT, "true", true);
|
||||||
|
AddOutputPort(Port::EXECUTION_PORT, "false", true);
|
||||||
|
|
||||||
|
// Initialiser les données internes
|
||||||
|
nlohmann::json j;
|
||||||
|
j["node_type"] = "branch";
|
||||||
|
j["version"] = 1;
|
||||||
|
SetInternalData(j);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void BranchNode::Initialize()
|
void BranchNode::Initialize()
|
||||||
{
|
{
|
||||||
|
// Charger les données sauvegardées
|
||||||
|
nlohmann::json j = GetInternalData();
|
||||||
|
|
||||||
|
// Vérifier la version pour compatibilité future
|
||||||
|
if (j.contains("version"))
|
||||||
|
{
|
||||||
|
int version = j["version"].get<int>();
|
||||||
|
// Gérer les migrations de version si nécessaire
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,32 @@
|
||||||
#include "i_script_node.h"
|
#include "i_script_node.h"
|
||||||
#include "i_story_project.h"
|
#include "i_story_project.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Nœud de branchement conditionnel simple
|
||||||
|
*
|
||||||
|
* Ce nœud évalue une condition booléenne et exécute l'une des deux branches.
|
||||||
|
* La condition provient d'un OperatorNode ou de toute autre source de données.
|
||||||
|
*
|
||||||
|
* Convention booléenne:
|
||||||
|
* - 0 = false
|
||||||
|
* - toute autre valeur = true
|
||||||
|
*
|
||||||
|
* Ports:
|
||||||
|
* - Entrée 0: Flux d'exécution (EXECUTION_PORT)
|
||||||
|
* - Entrée 1: Condition (DATA_PORT) - résultat d'un OperatorNode par exemple
|
||||||
|
* - Sortie 0: Branche TRUE (EXECUTION_PORT)
|
||||||
|
* - Sortie 1: Branche FALSE (EXECUTION_PORT)
|
||||||
|
*
|
||||||
|
* Utilisation typique:
|
||||||
|
* [Variable A] ──┐
|
||||||
|
* ├──> [OperatorNode >] ──> [BranchNode]
|
||||||
|
* [Variable B] ──┘ ↓ ↓
|
||||||
|
* TRUE FALSE
|
||||||
|
*/
|
||||||
class BranchNode : public BaseNode
|
class BranchNode : public BaseNode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
BranchNode(const std::string &type);
|
BranchNode(const std::string &type);
|
||||||
|
|
||||||
virtual void Initialize() override;
|
virtual void Initialize() override;
|
||||||
|
|
||||||
private:
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
#include "story_project.h"
|
#include "story_project.h"
|
||||||
#include "story_primitive.h"
|
#include "story_primitive.h"
|
||||||
#include "function_entry_node.h"
|
#include "function_entry_node.h"
|
||||||
|
#include "branch_node.h"
|
||||||
|
|
||||||
static const std::string OperatorNodeUuid = "0226fdac-8f7a-47d7-8584-b23aceb712ec";
|
static const std::string OperatorNodeUuid = "0226fdac-8f7a-47d7-8584-b23aceb712ec";
|
||||||
static const std::string CallFunctionNodeUuid = "02745f38-9b11-49fe-94b1-b2a6b78249fb";
|
static const std::string CallFunctionNodeUuid = "02745f38-9b11-49fe-94b1-b2a6b78249fb";
|
||||||
|
|
@ -24,7 +24,7 @@ static const std::string VariableNodeUuid = "020cca4e-9cdc-47e7-a6a5-53e4c9152ed
|
||||||
static const std::string PrintNodeUuid = "02ee27bc-ff1d-4f94-b700-eab55052ad1c";
|
static const std::string PrintNodeUuid = "02ee27bc-ff1d-4f94-b700-eab55052ad1c";
|
||||||
static const std::string SyscallNodeUuid = "02225cff-4975-400e-8130-41524d8af773";
|
static const std::string SyscallNodeUuid = "02225cff-4975-400e-8130-41524d8af773";
|
||||||
static const std::string FunctionEntryNodeUuid = "02fd145a-b3a6-43c2-83ce-6a187e6d4b5b";
|
static const std::string FunctionEntryNodeUuid = "02fd145a-b3a6-43c2-83ce-6a187e6d4b5b";
|
||||||
static const std::string DUMMY_a_prendre_Uuid = "027b723d-2327-4646-a17a-79ddc2e016e4";
|
static const std::string BranchNodeUuid = "027b723d-2327-4646-a17a-79ddc2e016e4";
|
||||||
|
|
||||||
typedef std::shared_ptr<BaseNode> (*GenericCreator)(const std::string &type);
|
typedef std::shared_ptr<BaseNode> (*GenericCreator)(const std::string &type);
|
||||||
|
|
||||||
|
|
@ -44,6 +44,8 @@ public:
|
||||||
registerNode<PrintNode>(PrintNodeUuid, std::make_shared<StoryPrimitive>("Print"));
|
registerNode<PrintNode>(PrintNodeUuid, std::make_shared<StoryPrimitive>("Print"));
|
||||||
registerNode<SyscallNode>(SyscallNodeUuid, std::make_shared<StoryPrimitive>("System call"));
|
registerNode<SyscallNode>(SyscallNodeUuid, std::make_shared<StoryPrimitive>("System call"));
|
||||||
registerNode<FunctionEntryNode>(FunctionEntryNodeUuid, std::make_shared<StoryPrimitive>("Function entry"));
|
registerNode<FunctionEntryNode>(FunctionEntryNodeUuid, std::make_shared<StoryPrimitive>("Function entry"));
|
||||||
|
registerNode<BranchNode>(BranchNodeUuid, std::make_shared<StoryPrimitive>("Branch"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~NodesFactory() = default;
|
~NodesFactory() = default;
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ add_executable(${PROJECT_NAME}
|
||||||
test_vm.cpp
|
test_vm.cpp
|
||||||
test_ast.cpp
|
test_ast.cpp
|
||||||
test_print_node.cpp
|
test_print_node.cpp
|
||||||
|
test_branch.cpp
|
||||||
|
|
||||||
../story-manager/src/nodes/base_node.cpp
|
../story-manager/src/nodes/base_node.cpp
|
||||||
../story-manager/src/nodes/branch_node.cpp
|
../story-manager/src/nodes/branch_node.cpp
|
||||||
|
|
|
||||||
672
core/tests/test_branch.cpp
Normal file
672
core/tests/test_branch.cpp
Normal file
|
|
@ -0,0 +1,672 @@
|
||||||
|
// ===================================================================
|
||||||
|
// test_branch_node.cpp
|
||||||
|
// Tests complets pour BranchNode avec différents types de conditions
|
||||||
|
// ===================================================================
|
||||||
|
|
||||||
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
#include "branch_node.h"
|
||||||
|
#include "variable_node.h"
|
||||||
|
#include "function_entry_node.h"
|
||||||
|
#include "operator_node.h"
|
||||||
|
#include "print_node.h"
|
||||||
|
#include "connection.h"
|
||||||
|
#include "ast_builder.h"
|
||||||
|
#include "assembly_generator_chip32_tac.h"
|
||||||
|
#include "chip32_machine.h"
|
||||||
|
#include "variable.h"
|
||||||
|
|
||||||
|
// ===================================================================
|
||||||
|
// TEST 1 : BranchNode avec condition booléenne directe (variable)
|
||||||
|
// ===================================================================
|
||||||
|
TEST_CASE("Branch with direct boolean variable", "[branch][boolean][variable]") {
|
||||||
|
std::cout << "\n=== Test: Branch with direct boolean variable ===\n";
|
||||||
|
|
||||||
|
// Variables
|
||||||
|
std::vector<std::shared_ptr<Variable>> variables;
|
||||||
|
|
||||||
|
// Condition = 1 (true)
|
||||||
|
auto varCondition = std::make_shared<Variable>("condition");
|
||||||
|
varCondition->SetIntegerValue(1);
|
||||||
|
variables.push_back(varCondition);
|
||||||
|
|
||||||
|
// Nodes
|
||||||
|
auto functionEntry = std::make_shared<FunctionEntryNode>("function-entry");
|
||||||
|
functionEntry->SetWeight(100);
|
||||||
|
|
||||||
|
auto varNode = std::make_shared<VariableNode>("var-condition");
|
||||||
|
varNode->SetVariable(varCondition);
|
||||||
|
|
||||||
|
auto branchNode = std::make_shared<BranchNode>("branch-node");
|
||||||
|
branchNode->Initialize();
|
||||||
|
|
||||||
|
auto printTrue = std::make_shared<PrintNode>("print-true");
|
||||||
|
printTrue->SetText("TRUE branch executed");
|
||||||
|
printTrue->Initialize();
|
||||||
|
|
||||||
|
auto printFalse = std::make_shared<PrintNode>("print-false");
|
||||||
|
printFalse->SetText("FALSE branch executed");
|
||||||
|
printFalse->Initialize();
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<BaseNode>> nodes = {
|
||||||
|
functionEntry,
|
||||||
|
varNode,
|
||||||
|
branchNode,
|
||||||
|
printTrue,
|
||||||
|
printFalse
|
||||||
|
};
|
||||||
|
|
||||||
|
// Connections
|
||||||
|
std::vector<std::shared_ptr<Connection>> connections;
|
||||||
|
|
||||||
|
// Execution: Entry → Branch
|
||||||
|
auto execConn = std::make_shared<Connection>();
|
||||||
|
execConn->outNodeId = functionEntry->GetId();
|
||||||
|
execConn->outPortIndex = 0;
|
||||||
|
execConn->inNodeId = branchNode->GetId();
|
||||||
|
execConn->inPortIndex = 0;
|
||||||
|
execConn->type = Connection::EXECUTION_LINK;
|
||||||
|
connections.push_back(execConn);
|
||||||
|
|
||||||
|
// Data: Variable → Branch.condition (port 1)
|
||||||
|
auto dataConn = std::make_shared<Connection>();
|
||||||
|
dataConn->outNodeId = varNode->GetId();
|
||||||
|
dataConn->outPortIndex = 0;
|
||||||
|
dataConn->inNodeId = branchNode->GetId();
|
||||||
|
dataConn->inPortIndex = 1;
|
||||||
|
dataConn->type = Connection::DATA_LINK;
|
||||||
|
connections.push_back(dataConn);
|
||||||
|
|
||||||
|
// Execution: Branch.true → PrintTrue
|
||||||
|
auto execTrue = std::make_shared<Connection>();
|
||||||
|
execTrue->outNodeId = branchNode->GetId();
|
||||||
|
execTrue->outPortIndex = 0;
|
||||||
|
execTrue->inNodeId = printTrue->GetId();
|
||||||
|
execTrue->inPortIndex = 0;
|
||||||
|
execTrue->type = Connection::EXECUTION_LINK;
|
||||||
|
connections.push_back(execTrue);
|
||||||
|
|
||||||
|
// Execution: Branch.false → PrintFalse
|
||||||
|
auto execFalse = std::make_shared<Connection>();
|
||||||
|
execFalse->outNodeId = branchNode->GetId();
|
||||||
|
execFalse->outPortIndex = 1;
|
||||||
|
execFalse->inNodeId = printFalse->GetId();
|
||||||
|
execFalse->inPortIndex = 0;
|
||||||
|
execFalse->type = Connection::EXECUTION_LINK;
|
||||||
|
connections.push_back(execFalse);
|
||||||
|
|
||||||
|
// Build AST
|
||||||
|
ASTBuilder builder(nodes, connections);
|
||||||
|
auto pathTree = builder.BuildAST();
|
||||||
|
|
||||||
|
// Generate Assembly using TAC
|
||||||
|
AssemblyGenerator::GeneratorContext context(
|
||||||
|
variables,
|
||||||
|
"2025-01-10 10:00:00",
|
||||||
|
"test-branch-bool-var",
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
1024
|
||||||
|
);
|
||||||
|
|
||||||
|
AssemblyGeneratorChip32TAC tacGen(context);
|
||||||
|
tacGen.GenerateCompleteProgram(nodes, pathTree);
|
||||||
|
|
||||||
|
std::string assembly = tacGen.GetAssembly().str();
|
||||||
|
|
||||||
|
std::cout << "\n--- Generated Assembly ---\n";
|
||||||
|
std::cout << assembly << std::endl;
|
||||||
|
|
||||||
|
// Verify
|
||||||
|
REQUIRE(assembly.find("DATA") != std::string::npos);
|
||||||
|
REQUIRE(assembly.find("CODE") != std::string::npos);
|
||||||
|
REQUIRE(assembly.find("branch_true") != std::string::npos);
|
||||||
|
REQUIRE(assembly.find("branch_false") != std::string::npos);
|
||||||
|
|
||||||
|
// Execute
|
||||||
|
std::cout << "\n--- Execution Output ---\n";
|
||||||
|
std::cout << "Expected: TRUE branch executed (condition = 1)\n";
|
||||||
|
std::cout << "Actual: ";
|
||||||
|
|
||||||
|
Chip32::Machine machine;
|
||||||
|
machine.QuickExecute(assembly);
|
||||||
|
|
||||||
|
std::cout << "\n✓ Test passed\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===================================================================
|
||||||
|
// TEST 2 : BranchNode avec OperatorNode (comparaison)
|
||||||
|
// ===================================================================
|
||||||
|
TEST_CASE("Branch with OperatorNode comparison", "[branch][operator][comparison]") {
|
||||||
|
std::cout << "\n=== Test: Branch with OperatorNode (A > B) ===\n";
|
||||||
|
|
||||||
|
// Variables
|
||||||
|
std::vector<std::shared_ptr<Variable>> variables;
|
||||||
|
|
||||||
|
auto varA = std::make_shared<Variable>("A");
|
||||||
|
varA->SetIntegerValue(10);
|
||||||
|
variables.push_back(varA);
|
||||||
|
|
||||||
|
auto varB = std::make_shared<Variable>("B");
|
||||||
|
varB->SetIntegerValue(5);
|
||||||
|
variables.push_back(varB);
|
||||||
|
|
||||||
|
// Nodes
|
||||||
|
auto functionEntry = std::make_shared<FunctionEntryNode>("function-entry");
|
||||||
|
functionEntry->SetWeight(100);
|
||||||
|
|
||||||
|
auto varNodeA = std::make_shared<VariableNode>("var-A");
|
||||||
|
varNodeA->SetVariable(varA);
|
||||||
|
|
||||||
|
auto varNodeB = std::make_shared<VariableNode>("var-B");
|
||||||
|
varNodeB->SetVariable(varB);
|
||||||
|
|
||||||
|
auto operatorNode = std::make_shared<OperatorNode>("operator-gt");
|
||||||
|
operatorNode->SetOperationType(OperatorNode::OperationType::GREATER_THAN);
|
||||||
|
operatorNode->Initialize();
|
||||||
|
|
||||||
|
auto branchNode = std::make_shared<BranchNode>("branch-node");
|
||||||
|
branchNode->Initialize();
|
||||||
|
|
||||||
|
auto printTrue = std::make_shared<PrintNode>("print-true");
|
||||||
|
printTrue->SetText("A is greater than B");
|
||||||
|
printTrue->Initialize();
|
||||||
|
|
||||||
|
auto printFalse = std::make_shared<PrintNode>("print-false");
|
||||||
|
printFalse->SetText("A is NOT greater than B");
|
||||||
|
printFalse->Initialize();
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<BaseNode>> nodes = {
|
||||||
|
functionEntry,
|
||||||
|
varNodeA,
|
||||||
|
varNodeB,
|
||||||
|
operatorNode,
|
||||||
|
branchNode,
|
||||||
|
printTrue,
|
||||||
|
printFalse
|
||||||
|
};
|
||||||
|
|
||||||
|
// Connections
|
||||||
|
std::vector<std::shared_ptr<Connection>> connections;
|
||||||
|
|
||||||
|
// Execution: Entry → Branch
|
||||||
|
auto execConn = std::make_shared<Connection>();
|
||||||
|
execConn->outNodeId = functionEntry->GetId();
|
||||||
|
execConn->outPortIndex = 0;
|
||||||
|
execConn->inNodeId = branchNode->GetId();
|
||||||
|
execConn->inPortIndex = 0;
|
||||||
|
execConn->type = Connection::EXECUTION_LINK;
|
||||||
|
connections.push_back(execConn);
|
||||||
|
|
||||||
|
// Data: A → Operator.in1
|
||||||
|
auto dataConn1 = std::make_shared<Connection>();
|
||||||
|
dataConn1->outNodeId = varNodeA->GetId();
|
||||||
|
dataConn1->outPortIndex = 0;
|
||||||
|
dataConn1->inNodeId = operatorNode->GetId();
|
||||||
|
dataConn1->inPortIndex = 0;
|
||||||
|
dataConn1->type = Connection::DATA_LINK;
|
||||||
|
connections.push_back(dataConn1);
|
||||||
|
|
||||||
|
// Data: B → Operator.in2
|
||||||
|
auto dataConn2 = std::make_shared<Connection>();
|
||||||
|
dataConn2->outNodeId = varNodeB->GetId();
|
||||||
|
dataConn2->outPortIndex = 0;
|
||||||
|
dataConn2->inNodeId = operatorNode->GetId();
|
||||||
|
dataConn2->inPortIndex = 1;
|
||||||
|
dataConn2->type = Connection::DATA_LINK;
|
||||||
|
connections.push_back(dataConn2);
|
||||||
|
|
||||||
|
// Data: Operator.out → Branch.condition
|
||||||
|
auto dataConn3 = std::make_shared<Connection>();
|
||||||
|
dataConn3->outNodeId = operatorNode->GetId();
|
||||||
|
dataConn3->outPortIndex = 0;
|
||||||
|
dataConn3->inNodeId = branchNode->GetId();
|
||||||
|
dataConn3->inPortIndex = 1;
|
||||||
|
dataConn3->type = Connection::DATA_LINK;
|
||||||
|
connections.push_back(dataConn3);
|
||||||
|
|
||||||
|
// Execution: Branch.true → PrintTrue
|
||||||
|
auto execTrue = std::make_shared<Connection>();
|
||||||
|
execTrue->outNodeId = branchNode->GetId();
|
||||||
|
execTrue->outPortIndex = 0;
|
||||||
|
execTrue->inNodeId = printTrue->GetId();
|
||||||
|
execTrue->inPortIndex = 0;
|
||||||
|
execTrue->type = Connection::EXECUTION_LINK;
|
||||||
|
connections.push_back(execTrue);
|
||||||
|
|
||||||
|
// Execution: Branch.false → PrintFalse
|
||||||
|
auto execFalse = std::make_shared<Connection>();
|
||||||
|
execFalse->outNodeId = branchNode->GetId();
|
||||||
|
execFalse->outPortIndex = 1;
|
||||||
|
execFalse->inNodeId = printFalse->GetId();
|
||||||
|
execFalse->inPortIndex = 0;
|
||||||
|
execFalse->type = Connection::EXECUTION_LINK;
|
||||||
|
connections.push_back(execFalse);
|
||||||
|
|
||||||
|
// Build and generate
|
||||||
|
ASTBuilder builder(nodes, connections);
|
||||||
|
auto pathTree = builder.BuildAST();
|
||||||
|
|
||||||
|
AssemblyGenerator::GeneratorContext context(
|
||||||
|
variables, "2025-01-10", "test-branch-operator", true, true, 1024
|
||||||
|
);
|
||||||
|
|
||||||
|
AssemblyGeneratorChip32TAC tacGen(context);
|
||||||
|
tacGen.GenerateCompleteProgram(nodes, pathTree);
|
||||||
|
|
||||||
|
std::string assembly = tacGen.GetAssembly().str();
|
||||||
|
|
||||||
|
std::cout << "\n--- Generated Assembly ---\n";
|
||||||
|
std::cout << assembly << std::endl;
|
||||||
|
|
||||||
|
// Verify TAC structure
|
||||||
|
REQUIRE(assembly.find("gt") != std::string::npos); // Greater Than opcode
|
||||||
|
REQUIRE(assembly.find("branch_true") != std::string::npos);
|
||||||
|
REQUIRE(assembly.find("branch_false") != std::string::npos);
|
||||||
|
|
||||||
|
// Execute
|
||||||
|
std::cout << "\n--- Execution Output ---\n";
|
||||||
|
std::cout << "Expected: A is greater than B (10 > 5)\n";
|
||||||
|
std::cout << "Actual: ";
|
||||||
|
|
||||||
|
Chip32::Machine machine;
|
||||||
|
machine.QuickExecute(assembly);
|
||||||
|
|
||||||
|
std::cout << "\n✓ Test passed\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===================================================================
|
||||||
|
// TEST 3 : Tester différentes valeurs (0 = false, autres = true)
|
||||||
|
// ===================================================================
|
||||||
|
TEST_CASE("Branch with various condition values", "[branch][values][convention]") {
|
||||||
|
std::cout << "\n=== Test: Branch with various condition values ===\n";
|
||||||
|
|
||||||
|
struct TestCase {
|
||||||
|
int conditionValue;
|
||||||
|
bool expectedTrue;
|
||||||
|
std::string description;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<TestCase> testCases = {
|
||||||
|
{0, false, "0 should be FALSE"},
|
||||||
|
{1, true, "1 should be TRUE"},
|
||||||
|
{42, true, "42 should be TRUE"},
|
||||||
|
{-5, true, "-5 should be TRUE"},
|
||||||
|
{100, true, "100 should be TRUE"}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const auto& test : testCases) {
|
||||||
|
std::cout << "\n--- Testing: " << test.description << " ---\n";
|
||||||
|
|
||||||
|
// Variables
|
||||||
|
std::vector<std::shared_ptr<Variable>> variables;
|
||||||
|
|
||||||
|
auto varCondition = std::make_shared<Variable>("condition");
|
||||||
|
varCondition->SetIntegerValue(test.conditionValue);
|
||||||
|
variables.push_back(varCondition);
|
||||||
|
|
||||||
|
// Nodes
|
||||||
|
auto functionEntry = std::make_shared<FunctionEntryNode>("function-entry");
|
||||||
|
functionEntry->SetWeight(100);
|
||||||
|
|
||||||
|
auto varNode = std::make_shared<VariableNode>("var-condition");
|
||||||
|
varNode->SetVariable(varCondition);
|
||||||
|
|
||||||
|
auto branchNode = std::make_shared<BranchNode>("branch-node");
|
||||||
|
branchNode->Initialize();
|
||||||
|
|
||||||
|
auto printTrue = std::make_shared<PrintNode>("print-true");
|
||||||
|
printTrue->SetText("TRUE");
|
||||||
|
printTrue->Initialize();
|
||||||
|
|
||||||
|
auto printFalse = std::make_shared<PrintNode>("print-false");
|
||||||
|
printFalse->SetText("FALSE");
|
||||||
|
printFalse->Initialize();
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<BaseNode>> nodes = {
|
||||||
|
functionEntry, varNode, branchNode, printTrue, printFalse
|
||||||
|
};
|
||||||
|
|
||||||
|
// Connections (même pattern que TEST 1)
|
||||||
|
std::vector<std::shared_ptr<Connection>> connections;
|
||||||
|
|
||||||
|
auto execConn = std::make_shared<Connection>();
|
||||||
|
execConn->outNodeId = functionEntry->GetId();
|
||||||
|
execConn->outPortIndex = 0;
|
||||||
|
execConn->inNodeId = branchNode->GetId();
|
||||||
|
execConn->inPortIndex = 0;
|
||||||
|
execConn->type = Connection::EXECUTION_LINK;
|
||||||
|
connections.push_back(execConn);
|
||||||
|
|
||||||
|
auto dataConn = std::make_shared<Connection>();
|
||||||
|
dataConn->outNodeId = varNode->GetId();
|
||||||
|
dataConn->outPortIndex = 0;
|
||||||
|
dataConn->inNodeId = branchNode->GetId();
|
||||||
|
dataConn->inPortIndex = 1;
|
||||||
|
dataConn->type = Connection::DATA_LINK;
|
||||||
|
connections.push_back(dataConn);
|
||||||
|
|
||||||
|
auto execTrue = std::make_shared<Connection>();
|
||||||
|
execTrue->outNodeId = branchNode->GetId();
|
||||||
|
execTrue->outPortIndex = 0;
|
||||||
|
execTrue->inNodeId = printTrue->GetId();
|
||||||
|
execTrue->inPortIndex = 0;
|
||||||
|
execTrue->type = Connection::EXECUTION_LINK;
|
||||||
|
connections.push_back(execTrue);
|
||||||
|
|
||||||
|
auto execFalse = std::make_shared<Connection>();
|
||||||
|
execFalse->outNodeId = branchNode->GetId();
|
||||||
|
execFalse->outPortIndex = 1;
|
||||||
|
execFalse->inNodeId = printFalse->GetId();
|
||||||
|
execFalse->inPortIndex = 0;
|
||||||
|
execFalse->type = Connection::EXECUTION_LINK;
|
||||||
|
connections.push_back(execFalse);
|
||||||
|
|
||||||
|
// Build and generate
|
||||||
|
ASTBuilder builder(nodes, connections);
|
||||||
|
auto pathTree = builder.BuildAST();
|
||||||
|
|
||||||
|
AssemblyGenerator::GeneratorContext context(
|
||||||
|
variables, "2025-01-10", "test-branch-values", false, true, 1024
|
||||||
|
);
|
||||||
|
|
||||||
|
AssemblyGeneratorChip32TAC tacGen(context);
|
||||||
|
tacGen.GenerateCompleteProgram(nodes, pathTree);
|
||||||
|
|
||||||
|
std::string assembly = tacGen.GetAssembly().str();
|
||||||
|
|
||||||
|
// Execute
|
||||||
|
Chip32::Machine machine;
|
||||||
|
machine.QuickExecute(assembly);
|
||||||
|
|
||||||
|
std::string output = machine.printOutput;
|
||||||
|
std::string expected = test.expectedTrue ? "TRUE" : "FALSE";
|
||||||
|
|
||||||
|
std::cout << "Condition value: " << test.conditionValue << "\n";
|
||||||
|
std::cout << "Expected: " << expected << ", Got: " << output << "\n";
|
||||||
|
|
||||||
|
REQUIRE(output.find(expected) != std::string::npos);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "\n✓ All value tests passed\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===================================================================
|
||||||
|
// TEST 4 : Tester tous les opérateurs de comparaison
|
||||||
|
// ===================================================================
|
||||||
|
TEST_CASE("Branch with all comparison operators", "[branch][operators][all]") {
|
||||||
|
std::cout << "\n=== Test: All comparison operators ===\n";
|
||||||
|
|
||||||
|
struct TestCase {
|
||||||
|
OperatorNode::OperationType op;
|
||||||
|
int a, b;
|
||||||
|
bool expectedTrue;
|
||||||
|
std::string description;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<TestCase> testCases = {
|
||||||
|
{OperatorNode::OperationType::EQUAL, 5, 5, true, "5 == 5"},
|
||||||
|
{OperatorNode::OperationType::EQUAL, 5, 10, false, "5 == 10"},
|
||||||
|
{OperatorNode::OperationType::NOT_EQUAL, 5, 10, true, "5 != 10"},
|
||||||
|
{OperatorNode::OperationType::NOT_EQUAL, 5, 5, false, "5 != 5"},
|
||||||
|
{OperatorNode::OperationType::GREATER_THAN, 10, 5, true, "10 > 5"},
|
||||||
|
{OperatorNode::OperationType::GREATER_THAN, 5, 10, false, "5 > 10"},
|
||||||
|
{OperatorNode::OperationType::LESS_THAN, 5, 10, true, "5 < 10"},
|
||||||
|
{OperatorNode::OperationType::LESS_THAN, 10, 5, false, "10 < 5"},
|
||||||
|
{OperatorNode::OperationType::GREATER_EQUAL, 10, 5, true, "10 >= 5"},
|
||||||
|
{OperatorNode::OperationType::GREATER_EQUAL, 5, 5, true, "5 >= 5"},
|
||||||
|
{OperatorNode::OperationType::GREATER_EQUAL, 5, 10, false, "5 >= 10"},
|
||||||
|
{OperatorNode::OperationType::LESS_EQUAL, 5, 10, true, "5 <= 10"},
|
||||||
|
{OperatorNode::OperationType::LESS_EQUAL, 5, 5, true, "5 <= 5"},
|
||||||
|
{OperatorNode::OperationType::LESS_EQUAL, 10, 5, false, "10 <= 5"}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const auto& test : testCases) {
|
||||||
|
std::cout << "\n--- Testing: " << test.description << " ---\n";
|
||||||
|
|
||||||
|
// Variables
|
||||||
|
std::vector<std::shared_ptr<Variable>> variables;
|
||||||
|
|
||||||
|
auto varA = std::make_shared<Variable>("A");
|
||||||
|
varA->SetIntegerValue(test.a);
|
||||||
|
variables.push_back(varA);
|
||||||
|
|
||||||
|
auto varB = std::make_shared<Variable>("B");
|
||||||
|
varB->SetIntegerValue(test.b);
|
||||||
|
variables.push_back(varB);
|
||||||
|
|
||||||
|
// Nodes (même structure que TEST 2)
|
||||||
|
auto functionEntry = std::make_shared<FunctionEntryNode>("function-entry");
|
||||||
|
functionEntry->SetWeight(100);
|
||||||
|
|
||||||
|
auto varNodeA = std::make_shared<VariableNode>("var-A");
|
||||||
|
varNodeA->SetVariable(varA);
|
||||||
|
|
||||||
|
auto varNodeB = std::make_shared<VariableNode>("var-B");
|
||||||
|
varNodeB->SetVariable(varB);
|
||||||
|
|
||||||
|
auto operatorNode = std::make_shared<OperatorNode>("operator");
|
||||||
|
operatorNode->SetOperationType(test.op);
|
||||||
|
operatorNode->Initialize();
|
||||||
|
|
||||||
|
auto branchNode = std::make_shared<BranchNode>("branch-node");
|
||||||
|
branchNode->Initialize();
|
||||||
|
|
||||||
|
auto printTrue = std::make_shared<PrintNode>("print-true");
|
||||||
|
printTrue->SetText("TRUE");
|
||||||
|
printTrue->Initialize();
|
||||||
|
|
||||||
|
auto printFalse = std::make_shared<PrintNode>("print-false");
|
||||||
|
printFalse->SetText("FALSE");
|
||||||
|
printFalse->Initialize();
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<BaseNode>> nodes = {
|
||||||
|
functionEntry, varNodeA, varNodeB, operatorNode, branchNode, printTrue, printFalse
|
||||||
|
};
|
||||||
|
|
||||||
|
// Connections (pattern complet)
|
||||||
|
std::vector<std::shared_ptr<Connection>> connections;
|
||||||
|
|
||||||
|
auto execConn = std::make_shared<Connection>();
|
||||||
|
execConn->outNodeId = functionEntry->GetId();
|
||||||
|
execConn->outPortIndex = 0;
|
||||||
|
execConn->inNodeId = branchNode->GetId();
|
||||||
|
execConn->inPortIndex = 0;
|
||||||
|
execConn->type = Connection::EXECUTION_LINK;
|
||||||
|
connections.push_back(execConn);
|
||||||
|
|
||||||
|
auto dataConn1 = std::make_shared<Connection>();
|
||||||
|
dataConn1->outNodeId = varNodeA->GetId();
|
||||||
|
dataConn1->outPortIndex = 0;
|
||||||
|
dataConn1->inNodeId = operatorNode->GetId();
|
||||||
|
dataConn1->inPortIndex = 0;
|
||||||
|
dataConn1->type = Connection::DATA_LINK;
|
||||||
|
connections.push_back(dataConn1);
|
||||||
|
|
||||||
|
auto dataConn2 = std::make_shared<Connection>();
|
||||||
|
dataConn2->outNodeId = varNodeB->GetId();
|
||||||
|
dataConn2->outPortIndex = 0;
|
||||||
|
dataConn2->inNodeId = operatorNode->GetId();
|
||||||
|
dataConn2->inPortIndex = 1;
|
||||||
|
dataConn2->type = Connection::DATA_LINK;
|
||||||
|
connections.push_back(dataConn2);
|
||||||
|
|
||||||
|
auto dataConn3 = std::make_shared<Connection>();
|
||||||
|
dataConn3->outNodeId = operatorNode->GetId();
|
||||||
|
dataConn3->outPortIndex = 0;
|
||||||
|
dataConn3->inNodeId = branchNode->GetId();
|
||||||
|
dataConn3->inPortIndex = 1;
|
||||||
|
dataConn3->type = Connection::DATA_LINK;
|
||||||
|
connections.push_back(dataConn3);
|
||||||
|
|
||||||
|
auto execTrue = std::make_shared<Connection>();
|
||||||
|
execTrue->outNodeId = branchNode->GetId();
|
||||||
|
execTrue->outPortIndex = 0;
|
||||||
|
execTrue->inNodeId = printTrue->GetId();
|
||||||
|
execTrue->inPortIndex = 0;
|
||||||
|
execTrue->type = Connection::EXECUTION_LINK;
|
||||||
|
connections.push_back(execTrue);
|
||||||
|
|
||||||
|
auto execFalse = std::make_shared<Connection>();
|
||||||
|
execFalse->outNodeId = branchNode->GetId();
|
||||||
|
execFalse->outPortIndex = 1;
|
||||||
|
execFalse->inNodeId = printFalse->GetId();
|
||||||
|
execFalse->inPortIndex = 0;
|
||||||
|
execFalse->type = Connection::EXECUTION_LINK;
|
||||||
|
connections.push_back(execFalse);
|
||||||
|
|
||||||
|
// Build and execute
|
||||||
|
ASTBuilder builder(nodes, connections);
|
||||||
|
auto pathTree = builder.BuildAST();
|
||||||
|
|
||||||
|
AssemblyGenerator::GeneratorContext context(
|
||||||
|
variables, "2025-01-10", "test-branch-op", false, true, 1024
|
||||||
|
);
|
||||||
|
|
||||||
|
AssemblyGeneratorChip32TAC tacGen(context);
|
||||||
|
tacGen.GenerateCompleteProgram(nodes, pathTree);
|
||||||
|
|
||||||
|
std::string assembly = tacGen.GetAssembly().str();
|
||||||
|
|
||||||
|
Chip32::Machine machine;
|
||||||
|
machine.QuickExecute(assembly);
|
||||||
|
|
||||||
|
std::string output = machine.printOutput;
|
||||||
|
std::string expected = test.expectedTrue ? "TRUE" : "FALSE";
|
||||||
|
|
||||||
|
std::cout << "Expected: " << expected << ", Got: " << output << "\n";
|
||||||
|
REQUIRE(output.find(expected) != std::string::npos);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "\n✓ All operator tests passed\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===================================================================
|
||||||
|
// TEST 5 : BranchNode avec résultat d'opération arithmétique
|
||||||
|
// ===================================================================
|
||||||
|
TEST_CASE("Branch with arithmetic operation result", "[branch][arithmetic]") {
|
||||||
|
std::cout << "\n=== Test: Branch with arithmetic result (5 - 5 = 0) ===\n";
|
||||||
|
|
||||||
|
// Variables
|
||||||
|
std::vector<std::shared_ptr<Variable>> variables;
|
||||||
|
|
||||||
|
auto varA = std::make_shared<Variable>("A");
|
||||||
|
varA->SetIntegerValue(5);
|
||||||
|
variables.push_back(varA);
|
||||||
|
|
||||||
|
auto varB = std::make_shared<Variable>("B");
|
||||||
|
varB->SetIntegerValue(5);
|
||||||
|
variables.push_back(varB);
|
||||||
|
|
||||||
|
// Nodes
|
||||||
|
auto functionEntry = std::make_shared<FunctionEntryNode>("function-entry");
|
||||||
|
functionEntry->SetWeight(100);
|
||||||
|
|
||||||
|
auto varNodeA = std::make_shared<VariableNode>("var-A");
|
||||||
|
varNodeA->SetVariable(varA);
|
||||||
|
|
||||||
|
auto varNodeB = std::make_shared<VariableNode>("var-B");
|
||||||
|
varNodeB->SetVariable(varB);
|
||||||
|
|
||||||
|
// Soustraction: 5 - 5 = 0 (false)
|
||||||
|
auto subNode = std::make_shared<OperatorNode>("operator-sub");
|
||||||
|
subNode->SetOperationType(OperatorNode::OperationType::SUBTRACT);
|
||||||
|
subNode->Initialize();
|
||||||
|
|
||||||
|
auto branchNode = std::make_shared<BranchNode>("branch-node");
|
||||||
|
branchNode->Initialize();
|
||||||
|
|
||||||
|
auto printTrue = std::make_shared<PrintNode>("print-true");
|
||||||
|
printTrue->SetText("Result is NON-ZERO");
|
||||||
|
printTrue->Initialize();
|
||||||
|
|
||||||
|
auto printFalse = std::make_shared<PrintNode>("print-false");
|
||||||
|
printFalse->SetText("Result is ZERO");
|
||||||
|
printFalse->Initialize();
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<BaseNode>> nodes = {
|
||||||
|
functionEntry, varNodeA, varNodeB, subNode, branchNode, printTrue, printFalse
|
||||||
|
};
|
||||||
|
|
||||||
|
// Connections
|
||||||
|
std::vector<std::shared_ptr<Connection>> connections;
|
||||||
|
|
||||||
|
auto execConn = std::make_shared<Connection>();
|
||||||
|
execConn->outNodeId = functionEntry->GetId();
|
||||||
|
execConn->outPortIndex = 0;
|
||||||
|
execConn->inNodeId = branchNode->GetId();
|
||||||
|
execConn->inPortIndex = 0;
|
||||||
|
execConn->type = Connection::EXECUTION_LINK;
|
||||||
|
connections.push_back(execConn);
|
||||||
|
|
||||||
|
auto dataConn1 = std::make_shared<Connection>();
|
||||||
|
dataConn1->outNodeId = varNodeA->GetId();
|
||||||
|
dataConn1->outPortIndex = 0;
|
||||||
|
dataConn1->inNodeId = subNode->GetId();
|
||||||
|
dataConn1->inPortIndex = 0;
|
||||||
|
dataConn1->type = Connection::DATA_LINK;
|
||||||
|
connections.push_back(dataConn1);
|
||||||
|
|
||||||
|
auto dataConn2 = std::make_shared<Connection>();
|
||||||
|
dataConn2->outNodeId = varNodeB->GetId();
|
||||||
|
dataConn2->outPortIndex = 0;
|
||||||
|
dataConn2->inNodeId = subNode->GetId();
|
||||||
|
dataConn2->inPortIndex = 1;
|
||||||
|
dataConn2->type = Connection::DATA_LINK;
|
||||||
|
connections.push_back(dataConn2);
|
||||||
|
|
||||||
|
auto dataConn3 = std::make_shared<Connection>();
|
||||||
|
dataConn3->outNodeId = subNode->GetId();
|
||||||
|
dataConn3->outPortIndex = 0;
|
||||||
|
dataConn3->inNodeId = branchNode->GetId();
|
||||||
|
dataConn3->inPortIndex = 1;
|
||||||
|
dataConn3->type = Connection::DATA_LINK;
|
||||||
|
connections.push_back(dataConn3);
|
||||||
|
|
||||||
|
auto execTrue = std::make_shared<Connection>();
|
||||||
|
execTrue->outNodeId = branchNode->GetId();
|
||||||
|
execTrue->outPortIndex = 0;
|
||||||
|
execTrue->inNodeId = printTrue->GetId();
|
||||||
|
execTrue->inPortIndex = 0;
|
||||||
|
execTrue->type = Connection::EXECUTION_LINK;
|
||||||
|
connections.push_back(execTrue);
|
||||||
|
|
||||||
|
auto execFalse = std::make_shared<Connection>();
|
||||||
|
execFalse->outNodeId = branchNode->GetId();
|
||||||
|
execFalse->outPortIndex = 1;
|
||||||
|
execFalse->inNodeId = printFalse->GetId();
|
||||||
|
execFalse->inPortIndex = 0;
|
||||||
|
execFalse->type = Connection::EXECUTION_LINK;
|
||||||
|
connections.push_back(execFalse);
|
||||||
|
|
||||||
|
// Build and execute
|
||||||
|
ASTBuilder builder(nodes, connections);
|
||||||
|
auto pathTree = builder.BuildAST();
|
||||||
|
|
||||||
|
AssemblyGenerator::GeneratorContext context(
|
||||||
|
variables, "2025-01-10", "test-branch-arithmetic", true, true, 1024
|
||||||
|
);
|
||||||
|
|
||||||
|
AssemblyGeneratorChip32TAC tacGen(context);
|
||||||
|
tacGen.GenerateCompleteProgram(nodes, pathTree);
|
||||||
|
|
||||||
|
std::string assembly = tacGen.GetAssembly().str();
|
||||||
|
|
||||||
|
std::cout << "\n--- Generated Assembly ---\n";
|
||||||
|
std::cout << assembly << std::endl;
|
||||||
|
|
||||||
|
// Verify subtraction is present
|
||||||
|
REQUIRE(assembly.find("sub") != std::string::npos);
|
||||||
|
|
||||||
|
// Execute
|
||||||
|
std::cout << "\n--- Execution Output ---\n";
|
||||||
|
std::cout << "Expected: Result is ZERO (5 - 5 = 0)\n";
|
||||||
|
std::cout << "Actual: ";
|
||||||
|
|
||||||
|
Chip32::Machine machine;
|
||||||
|
machine.QuickExecute(assembly);
|
||||||
|
|
||||||
|
std::string output = machine.printOutput;
|
||||||
|
REQUIRE(output.find("ZERO") != std::string::npos);
|
||||||
|
|
||||||
|
std::cout << "\n✓ Test passed\n";
|
||||||
|
}
|
||||||
|
|
@ -148,6 +148,7 @@ set(SRCS
|
||||||
src/node_editor/operator_node_widget.cpp
|
src/node_editor/operator_node_widget.cpp
|
||||||
src/node_editor/print_node_widget.cpp
|
src/node_editor/print_node_widget.cpp
|
||||||
src/node_editor/syscall_node_widget.cpp
|
src/node_editor/syscall_node_widget.cpp
|
||||||
|
src/node_editor/branch_node_widget.cpp
|
||||||
|
|
||||||
src/gui.cpp
|
src/gui.cpp
|
||||||
src/media_converter.cpp
|
src/media_converter.cpp
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[Window][WindowOverViewport_11111111]
|
[Window][WindowOverViewport_11111111]
|
||||||
Pos=60,26
|
Pos=60,26
|
||||||
Size=1220,836
|
Size=1429,832
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
|
|
||||||
[Window][Debug##Default]
|
[Window][Debug##Default]
|
||||||
|
|
@ -9,32 +9,32 @@ Size=400,400
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
|
|
||||||
[Window][Library Manager]
|
[Window][Library Manager]
|
||||||
Pos=630,26
|
Pos=554,26
|
||||||
Size=650,518
|
Size=935,607
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000002,0
|
DockId=0x00000002,0
|
||||||
|
|
||||||
[Window][Console]
|
[Window][Console]
|
||||||
Pos=60,546
|
Pos=60,635
|
||||||
Size=628,316
|
Size=618,223
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000004,0
|
DockId=0x00000004,0
|
||||||
|
|
||||||
[Window][Emulator]
|
[Window][Emulator]
|
||||||
Pos=630,26
|
Pos=554,26
|
||||||
Size=650,518
|
Size=935,607
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000002,5
|
DockId=0x00000002,5
|
||||||
|
|
||||||
[Window][Code viewer]
|
[Window][Code viewer]
|
||||||
Pos=630,26
|
Pos=554,26
|
||||||
Size=650,518
|
Size=935,607
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000002,4
|
DockId=0x00000002,4
|
||||||
|
|
||||||
[Window][Resources]
|
[Window][Resources]
|
||||||
Pos=630,26
|
Pos=554,26
|
||||||
Size=650,518
|
Size=935,607
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000002,1
|
DockId=0x00000002,1
|
||||||
|
|
||||||
|
|
@ -50,36 +50,36 @@ Size=150,42
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
|
|
||||||
[Window][Variables]
|
[Window][Variables]
|
||||||
Pos=690,546
|
Pos=680,635
|
||||||
Size=590,316
|
Size=809,223
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000005,0
|
DockId=0x00000005,0
|
||||||
|
|
||||||
[Window][CPU]
|
[Window][CPU]
|
||||||
Pos=630,26
|
Pos=554,26
|
||||||
Size=650,518
|
Size=935,607
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000002,2
|
DockId=0x00000002,2
|
||||||
|
|
||||||
[Window][RAM view]
|
[Window][RAM view]
|
||||||
Pos=630,26
|
Pos=554,26
|
||||||
Size=650,518
|
Size=935,607
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000002,3
|
DockId=0x00000002,3
|
||||||
|
|
||||||
[Window][Properties]
|
[Window][Properties]
|
||||||
Pos=690,546
|
Pos=680,635
|
||||||
Size=590,316
|
Size=809,223
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000005,1
|
DockId=0x00000005,1
|
||||||
|
|
||||||
[Window][ToolBar]
|
[Window][ToolBar]
|
||||||
Pos=0,26
|
Pos=0,26
|
||||||
Size=60,836
|
Size=60,832
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
|
|
||||||
[Window][QuitConfirm]
|
[Window][QuitConfirm]
|
||||||
Pos=508,383
|
Pos=508,312
|
||||||
Size=264,96
|
Size=264,96
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
|
|
||||||
|
|
@ -90,13 +90,13 @@ Collapsed=0
|
||||||
|
|
||||||
[Window][Module editor]
|
[Window][Module editor]
|
||||||
Pos=60,26
|
Pos=60,26
|
||||||
Size=568,518
|
Size=492,607
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000001,0
|
DockId=0x00000001,0
|
||||||
|
|
||||||
[Window][Story editor]
|
[Window][Story editor]
|
||||||
Pos=60,26
|
Pos=60,26
|
||||||
Size=568,518
|
Size=492,607
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000001,1
|
DockId=0x00000001,1
|
||||||
|
|
||||||
|
|
@ -106,8 +106,8 @@ Size=687,422
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
|
|
||||||
[Window][Error List]
|
[Window][Error List]
|
||||||
Pos=60,546
|
Pos=60,635
|
||||||
Size=628,316
|
Size=618,223
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000004,1
|
DockId=0x00000004,1
|
||||||
|
|
||||||
|
|
@ -155,11 +155,11 @@ Column 2 Weight=1.0000
|
||||||
Column 3 Width=60
|
Column 3 Width=60
|
||||||
|
|
||||||
[Docking][Data]
|
[Docking][Data]
|
||||||
DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=60,26 Size=1220,836 Split=Y
|
DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=60,26 Size=1429,832 Split=Y
|
||||||
DockNode ID=0x00000007 Parent=0x08BD597D SizeRef=1220,549 Split=X
|
DockNode ID=0x00000007 Parent=0x08BD597D SizeRef=1220,469 Split=X
|
||||||
DockNode ID=0x00000001 Parent=0x00000007 SizeRef=1144,694 CentralNode=1 Selected=0x93ADCAAB
|
DockNode ID=0x00000001 Parent=0x00000007 SizeRef=492,694 CentralNode=1 Selected=0x93ADCAAB
|
||||||
DockNode ID=0x00000002 Parent=0x00000007 SizeRef=650,694 Selected=0xE5897A33
|
DockNode ID=0x00000002 Parent=0x00000007 SizeRef=935,694 Selected=0x63869CAF
|
||||||
DockNode ID=0x00000008 Parent=0x08BD597D SizeRef=1220,316 Split=X Selected=0xEA83D666
|
DockNode ID=0x00000008 Parent=0x08BD597D SizeRef=1220,223 Split=X Selected=0xEA83D666
|
||||||
DockNode ID=0x00000004 Parent=0x00000008 SizeRef=616,192 Selected=0xEA83D666
|
DockNode ID=0x00000004 Parent=0x00000008 SizeRef=621,192 Selected=0xEA83D666
|
||||||
DockNode ID=0x00000005 Parent=0x00000008 SizeRef=578,192 Selected=0x8C72BEA8
|
DockNode ID=0x00000005 Parent=0x00000008 SizeRef=813,192 Selected=0x8C72BEA8
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@
|
||||||
#include "print_node_widget.h"
|
#include "print_node_widget.h"
|
||||||
#include "syscall_node_widget.h"
|
#include "syscall_node_widget.h"
|
||||||
#include "function_entry_widget.h"
|
#include "function_entry_widget.h"
|
||||||
|
#include "branch_node_widget.h"
|
||||||
|
|
||||||
MainWindow::MainWindow(ILogger& logger, EventBus& eventBus, AppController& appController)
|
MainWindow::MainWindow(ILogger& logger, EventBus& eventBus, AppController& appController)
|
||||||
: m_logger(logger)
|
: m_logger(logger)
|
||||||
|
|
@ -74,6 +74,7 @@ MainWindow::MainWindow(ILogger& logger, EventBus& eventBus, AppController& appCo
|
||||||
m_widgetFactory.registerNode<PrintNodeWidget>(PrintNodeUuid);
|
m_widgetFactory.registerNode<PrintNodeWidget>(PrintNodeUuid);
|
||||||
m_widgetFactory.registerNode<SyscallNodeWidget>(SyscallNodeUuid);
|
m_widgetFactory.registerNode<SyscallNodeWidget>(SyscallNodeUuid);
|
||||||
m_widgetFactory.registerNode<FunctionEntryWidget>(FunctionEntryNodeUuid);
|
m_widgetFactory.registerNode<FunctionEntryWidget>(FunctionEntryNodeUuid);
|
||||||
|
m_widgetFactory.registerNode<BranchNodeWidget>(BranchNodeUuid);
|
||||||
|
|
||||||
m_eventBus.Subscribe<OpenProjectEvent>([this](const OpenProjectEvent &event) {
|
m_eventBus.Subscribe<OpenProjectEvent>([this](const OpenProjectEvent &event) {
|
||||||
OpenProject(event.GetUuid());
|
OpenProject(event.GetUuid());
|
||||||
|
|
|
||||||
54
story-editor/src/node_editor/branch_node_widget.cpp
Normal file
54
story-editor/src/node_editor/branch_node_widget.cpp
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
#include "branch_node_widget.h"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
#include "IconsMaterialDesignIcons.h"
|
||||||
|
#include "story_project.h"
|
||||||
|
|
||||||
|
BranchNodeWidget::BranchNodeWidget(IStoryManager &manager, std::shared_ptr<BaseNode> node)
|
||||||
|
: BaseNodeWidget(manager, node)
|
||||||
|
{
|
||||||
|
m_branchNode = std::dynamic_pointer_cast<BranchNode>(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BranchNodeWidget::Initialize()
|
||||||
|
{
|
||||||
|
BaseNodeWidget::Initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BranchNodeWidget::DrawProperties(std::shared_ptr<IStoryProject> story)
|
||||||
|
{
|
||||||
|
ImGui::AlignTextToFramePadding();
|
||||||
|
|
||||||
|
// Informations sur le nœud de branchement
|
||||||
|
ImGui::SeparatorText("Branch Node Properties");
|
||||||
|
|
||||||
|
ImGui::TextWrapped("This node evaluates a boolean condition and executes "
|
||||||
|
"one of two paths based on the result.");
|
||||||
|
|
||||||
|
ImGui::Spacing();
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::Spacing();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BranchNodeWidget::Draw()
|
||||||
|
{
|
||||||
|
// Icône et texte du nœud
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.8f, 0.2f, 1.0f));
|
||||||
|
ImGui::Text(ICON_MDI_SOURCE_BRANCH " Branch");
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
|
||||||
|
ImGui::Spacing();
|
||||||
|
|
||||||
|
// Affichage de la condition
|
||||||
|
ImGui::TextColored(ImVec4(0.8f, 0.8f, 0.8f, 1.0f), "if (condition)");
|
||||||
|
|
||||||
|
ImGui::Spacing();
|
||||||
|
|
||||||
|
// Affichage visuel des branches
|
||||||
|
ImGui::BeginGroup();
|
||||||
|
{
|
||||||
|
ImGui::TextColored(ImVec4(0.3f, 1.0f, 0.3f, 1.0f), ICON_MDI_CHECK " TRUE");
|
||||||
|
ImGui::TextColored(ImVec4(1.0f, 0.3f, 0.3f, 1.0f), ICON_MDI_CLOSE " FALSE");
|
||||||
|
}
|
||||||
|
ImGui::EndGroup();
|
||||||
|
}
|
||||||
36
story-editor/src/node_editor/branch_node_widget.h
Normal file
36
story-editor/src/node_editor/branch_node_widget.h
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "base_node_widget.h"
|
||||||
|
#include "i_story_manager.h"
|
||||||
|
#include "i_story_project.h"
|
||||||
|
#include "gui.h"
|
||||||
|
#include "branch_node.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Widget pour le nœud Branch (If/Else)
|
||||||
|
*
|
||||||
|
* Gère l'affichage et les propriétés d'un nœud de branchement conditionnel simple.
|
||||||
|
* La condition est évaluée selon la convention: 0 = false, toute autre valeur = true
|
||||||
|
*
|
||||||
|
* Ports:
|
||||||
|
* - Entrée 0: Flux d'exécution
|
||||||
|
* - Entrée 1: Condition booléenne (provient généralement d'un OperatorNode)
|
||||||
|
* - Sortie 0: Branche TRUE (condition != 0)
|
||||||
|
* - Sortie 1: Branche FALSE (condition == 0)
|
||||||
|
*/
|
||||||
|
class BranchNodeWidget : public BaseNodeWidget
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BranchNodeWidget(IStoryManager &manager, std::shared_ptr<BaseNode> node);
|
||||||
|
|
||||||
|
void Draw() override;
|
||||||
|
void DrawProperties(std::shared_ptr<IStoryProject> story) override;
|
||||||
|
void Initialize() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<BranchNode> m_branchNode;
|
||||||
|
};
|
||||||
Loading…
Reference in a new issue