From 741a3c633ee15d3909fe2f4fd3aaba03c2cbaebe Mon Sep 17 00:00:00 2001 From: "anthony@rabine.fr" Date: Mon, 6 Oct 2025 15:00:37 +0200 Subject: [PATCH] Fixed data connection, compilation order and print format --- core/chip32/chip32_machine.h | 151 ++++++++------ .../compiler/assembly_generator_chip32_tac.h | 34 ++-- core/story-manager/src/compiler/ast_builder.h | 6 + core/story-manager/src/compiler/tac.h | 88 ++++++-- core/story-manager/src/nodes/connection.cpp | 18 +- core/story-manager/src/nodes/connection.h | 25 ++- core/story-manager/src/nodes/print_node.h | 8 + .../story-manager/src/nodes/variable_node.cpp | 31 ++- core/story-manager/src/nodes/variable_node.h | 2 + core/story-manager/src/story_project.cpp | 46 ++++- story-editor/imgui.ini | 46 ++--- story-editor/src/app/app_controller.cpp | 110 ++-------- story-editor/src/app/app_controller.h | 2 +- story-editor/src/main_window.cpp | 2 +- .../src/node_editor/node_editor_page.h | 31 --- .../src/node_editor/node_editor_window.cpp | 188 ++---------------- 16 files changed, 358 insertions(+), 430 deletions(-) diff --git a/core/chip32/chip32_machine.h b/core/chip32/chip32_machine.h index a2c51c1..90c7a13 100644 --- a/core/chip32/chip32_machine.h +++ b/core/chip32/chip32_machine.h @@ -33,7 +33,7 @@ public: } // Lecture d'une chaîne depuis la mémoire (non statique maintenant) - std::string GetStringFromMemory(chip32_ctx_t *ctx, uint32_t addr) + static std::string GetStringFromMemory(chip32_ctx_t *ctx, uint32_t addr) { if (!ctx) { throw std::runtime_error("Invalid context in GetStringFromMemory"); @@ -73,66 +73,101 @@ public: } } - // Formatter avec nombre variable d'arguments (non statique) - std::string FormatString(const std::string& format, - const std::vector& args) + static std::string FormatStringWithPlaceholders(chip32_ctx_t *ctx, + const std::string& format, + const std::vector& args) { - if (args.empty()) { - return format; - } - - std::vector buffer(1024); - int result = -1; + std::ostringstream result; + size_t pos = 0; - switch (args.size()) { - case 1: - result = std::snprintf(buffer.data(), buffer.size(), - format.c_str(), args[0]); - break; - case 2: - result = std::snprintf(buffer.data(), buffer.size(), - format.c_str(), args[0], args[1]); - break; - case 3: - result = std::snprintf(buffer.data(), buffer.size(), - format.c_str(), args[0], args[1], args[2]); - break; - case 4: - result = std::snprintf(buffer.data(), buffer.size(), - format.c_str(), args[0], args[1], args[2], args[3]); - break; - default: - throw std::runtime_error("Too many arguments for printf (max 4)"); - } - - if (result < 0) { - throw std::runtime_error("Error formatting string"); - } - - if (static_cast(result) >= buffer.size()) { - buffer.resize(result + 1); - - switch (args.size()) { - case 1: - std::snprintf(buffer.data(), buffer.size(), - format.c_str(), args[0]); - break; - case 2: - std::snprintf(buffer.data(), buffer.size(), - format.c_str(), args[0], args[1]); - break; - case 3: - std::snprintf(buffer.data(), buffer.size(), - format.c_str(), args[0], args[1], args[2]); - break; - case 4: - std::snprintf(buffer.data(), buffer.size(), - format.c_str(), args[0], args[1], args[2], args[3]); - break; + while (pos < format.length()) { + // Chercher le prochain placeholder '{' + if (format[pos] == '{' && pos + 1 < format.length()) { + char nextChar = format[pos + 1]; + + // Vérifier si c'est un placeholder valide {0} à {3} + if (nextChar >= '0' && nextChar <= '3') { + int argIndex = nextChar - '0'; + + // Vérifier si on a assez d'arguments + if (argIndex >= static_cast(args.size())) { + result << "{" << argIndex << ":?}"; // Argument manquant + pos += 2; + continue; + } + + uint32_t argValue = args[argIndex]; + + // Vérifier s'il y a un type spécifié {:d}, {:s}, {:f}, {:x} + if (pos + 3 < format.length() && format[pos + 2] == ':') { + char typeChar = format[pos + 3]; + + // Vérifier si le placeholder se termine bien par '}' + if (pos + 4 < format.length() && format[pos + 4] == '}') { + // Parser le type et formater + switch (typeChar) { + case 'd': // Entier décimal signé + case 'i': + result << static_cast(argValue); + break; + + case 'u': // Entier non signé + result << argValue; + break; + + case 'x': // Hexadécimal minuscule + result << "0x" << std::hex << argValue << std::dec; + break; + + case 'X': // Hexadécimal majuscule + result << "0x" << std::hex << std::uppercase + << argValue << std::nouppercase << std::dec; + break; + + case 's': // String (adresse) + try { + result << GetStringFromMemory(ctx, argValue); + } catch (const std::exception& e) { + result << ""; + } + break; + + case 'f': // Float + { + float floatValue; + std::memcpy(&floatValue, &argValue, sizeof(float)); + result << floatValue; + break; + } + + case 'c': // Caractère + result << static_cast(argValue); + break; + + default: + // Type inconnu, afficher tel quel + result << "{" << argIndex << ":" << typeChar << "}"; + } + + pos += 5; // Avancer de "{0:d}" + continue; + } + } + // Format court {0} sans type → défaut: entier + else if (pos + 2 < format.length() && format[pos + 2] == '}') { + result << static_cast(argValue); + pos += 3; // Avancer de "{0}" + continue; + } + } } + + // Caractère normal, copier tel quel + result << format[pos]; + pos++; } - - return std::string(buffer.data()); + + return result.str(); } // Handler de syscall (méthode membre, non statique) @@ -149,7 +184,7 @@ public: args.push_back(ctx->registers[R2 + i]); } - printOutput = FormatString(format, args); + printOutput = FormatStringWithPlaceholders(ctx, format, args); std::cout << "[SYSCALL PRINT] " << printOutput << std::endl; } else if (code == 5) // WAIT diff --git a/core/story-manager/src/compiler/assembly_generator_chip32_tac.h b/core/story-manager/src/compiler/assembly_generator_chip32_tac.h index 416f671..feacfaf 100644 --- a/core/story-manager/src/compiler/assembly_generator_chip32_tac.h +++ b/core/story-manager/src/compiler/assembly_generator_chip32_tac.h @@ -284,9 +284,27 @@ private: m_assembly << " lcons " << targetReg << ", " << op->GetValue() << "\n"; return targetReg; - case TACOperand::Type::VARIABLE: - m_assembly << " load " << targetReg << ", $" << op->GetValue() << ", 4\n"; + case TACOperand::Type::VARIABLE: { + std::shared_ptr var = nullptr; + + // Chercher la variable par son label + for (const auto& v : m_context.variables) { + if (v->GetLabel() == op->GetValue()) { + var = v; + break; + } + } + + if (var && var->GetValueType() == Variable::ValueType::STRING) { + // Pour les strings, charger l'ADRESSE + m_assembly << " lcons " << targetReg << ", $" << op->GetValue() << "\n"; + } else { + // Pour les autres types, charger la VALEUR + m_assembly << " load " << targetReg << ", $" << op->GetValue() << ", 4\n"; + } return targetReg; + + } case TACOperand::Type::TEMPORARY: { auto it = m_tempLocations.find(op->GetValue()); @@ -541,17 +559,7 @@ private: switch (v->GetValueType()) { case Variable::ValueType::STRING: { std::string value = v->GetValue(); - - // Convertir {0} {1} {2} {3} en %d - for (int i = 0; i < 4; ++i) { - std::string placeholder = "{" + std::to_string(i) + "}"; - size_t pos = 0; - while ((pos = value.find(placeholder, pos)) != std::string::npos) { - value.replace(pos, placeholder.length(), "%d"); - pos += 2; - } - } - + m_assembly << "$" << v->GetLabel() << " DC8, \"" << value << "\" ; " << v->GetVariableName() << "\n"; break; diff --git a/core/story-manager/src/compiler/ast_builder.h b/core/story-manager/src/compiler/ast_builder.h index db4e3a8..0e271c1 100644 --- a/core/story-manager/src/compiler/ast_builder.h +++ b/core/story-manager/src/compiler/ast_builder.h @@ -183,10 +183,16 @@ public: // Maintenant, on va ajouter les connexions de données for (const auto& conn : m_connections) { + std::cout << ">>> ASTBuilder: Processing connection from " << conn->outNodeId + << " to " << conn->inNodeId + << " type=" << conn->type << " (0=EXEC, 1=DATA)" << std::endl; + // Ne traiter que les connexions DATA_LINK if (conn->type != Connection::DATA_LINK) { continue; } + + std::cout << " -> Adding DATA connection!" << std::endl; auto outNode = nodeMap[conn->outNodeId]; auto inNode = nodeMap[conn->inNodeId]; diff --git a/core/story-manager/src/compiler/tac.h b/core/story-manager/src/compiler/tac.h index b31b454..1a7d818 100644 --- a/core/story-manager/src/compiler/tac.h +++ b/core/story-manager/src/compiler/tac.h @@ -460,10 +460,19 @@ private: std::shared_ptr GenerateVariableNode(std::shared_ptr node) { auto* varNode = node->GetAs(); - if (!varNode) return nullptr; + if (!varNode) { + std::cout << " ERROR: node is not a VariableNode!\n"; + return nullptr; + } auto var = varNode->GetVariable(); - if (!var) return nullptr; + + if (!var) { + std::cout << " ERROR: Variable is NULL for node " << varNode->GetId() + << " (UUID: " << varNode->GetVariableUuid() << ")\n"; + std::cout << " This should have been resolved before TAC generation!\n"; + return nullptr; + } // Créer une opérande qui référence la variable return std::make_shared( @@ -552,17 +561,12 @@ private: std::cout << " GeneratePrintNode: START\n"; - // Créer l'opérande pour la chaîne de format - auto formatOperand = std::make_shared( - TACOperand::Type::VARIABLE, - printNode->GetLabel() - ); - - std::cout << " Format string label: " << printNode->GetLabel() << "\n"; - std::cout << " Number of data inputs: " << node->dataInputs.size() << "\n"; - - // Évaluer tous les arguments + // RÉCUPÉRER ET CONVERTIR LE FORMAT STRING + std::string formatString = printNode->GetText(); + + // Évaluer tous les arguments et déterminer leurs types std::vector> args; + std::vector argTypes; // Collecter et trier les inputs par port index std::vector>> sortedInputs; @@ -574,18 +578,76 @@ private: std::sort(sortedInputs.begin(), sortedInputs.end(), [](const auto& a, const auto& b) { return a.first < b.first; }); - // Générer le code pour chaque argument + // Générer le code pour chaque argument ET récupérer son type for (const auto& [port, inputNode] : sortedInputs) { std::cout << " Processing input port " << port << "\n"; auto argOperand = GenerateNode(inputNode); if (argOperand) { std::cout << " -> Got operand: " << argOperand->ToString() << "\n"; args.push_back(argOperand); + + // DÉTERMINER LE TYPE DE L'ARGUMENT + Variable::ValueType argType = Variable::ValueType::INTEGER; // défaut + + if (inputNode->IsType()) { + auto* varNode = inputNode->GetAs(); + auto var = varNode->GetVariable(); + if (var) { + argType = var->GetValueType(); + std::cout << " -> Variable type: " + << Variable::ValueTypeToString(argType) << "\n"; + } + } + // Pour les OperatorNode, le résultat est toujours un INTEGER + else if (inputNode->IsType()) { + argType = Variable::ValueType::INTEGER; + } + + argTypes.push_back(argType); } } std::cout << " Total args collected: " << args.size() << "\n"; + // CONVERTIR LES PLACEHOLDERS EN FONCTION DU TYPE + for (size_t i = 0; i < argTypes.size() && i < 4; i++) { + std::string placeholder = "{" + std::to_string(i) + "}"; + std::string formatSpec; + + switch (argTypes[i]) { + case Variable::ValueType::STRING: + formatSpec = "{" + std::to_string(i) + ":s}"; + break; + case Variable::ValueType::INTEGER: + formatSpec = "{" + std::to_string(i) + ":d}"; + break; + case Variable::ValueType::FLOAT: + formatSpec = "{" + std::to_string(i) + ":f}"; + break; + default: + formatSpec = "{" + std::to_string(i) + ":d}"; + } + + // Remplacer {0} par {0:d} ou {0:s} + size_t pos = formatString.find(placeholder); + if (pos != std::string::npos) { + formatString.replace(pos, placeholder.length(), formatSpec); + } + } + + // METTRE À JOUR LE FORMAT STRING DANS LA VARIABLE + auto formatVar = printNode->GetVariable(printNode->GetLabel()); + if (formatVar) { + formatVar->SetTextValue(formatString); + std::cout << " Updated format string to: " << formatString << "\n"; + } + + // Créer l'opérande pour la chaîne de format (avec le format mis à jour) + auto formatOperand = std::make_shared( + TACOperand::Type::VARIABLE, + printNode->GetLabel() + ); + // Générer les instructions PARAM pour chaque argument for (size_t i = 0; i < args.size(); i++) { std::cout << " Generating PARAM instruction [" << i << "] for " diff --git a/core/story-manager/src/nodes/connection.cpp b/core/story-manager/src/nodes/connection.cpp index 266165c..ac2a1c3 100644 --- a/core/story-manager/src/nodes/connection.cpp +++ b/core/story-manager/src/nodes/connection.cpp @@ -2,11 +2,12 @@ void to_json(nlohmann::json &j, const Connection &p) { j = nlohmann::json{ - {"outNodeId", p.outNodeId }, - {"outPortIndex", static_cast(p.outPortIndex)}, - {"inNodeId", p.inNodeId}, - {"inPortIndex", static_cast(p.inPortIndex)}, - }; + {"outNodeId", p.outNodeId }, + {"outPortIndex", static_cast(p.outPortIndex)}, + {"inNodeId", p.inNodeId}, + {"inPortIndex", static_cast(p.inPortIndex)}, + {"type", static_cast(p.type)} + }; } void from_json(const nlohmann::json &j, Connection &p) { @@ -15,4 +16,11 @@ void from_json(const nlohmann::json &j, Connection &p) { p.inNodeId = j["inNodeId"].get(); p.outPortIndex = j["outPortIndex"].get(); p.inPortIndex = j["inPortIndex"].get(); + + if (j.contains("type")) { + p.type = static_cast(j["type"].get()); + } else { + // Par défaut EXECUTION_LINK pour les anciens fichiers + p.type = Connection::EXECUTION_LINK; + } } diff --git a/core/story-manager/src/nodes/connection.h b/core/story-manager/src/nodes/connection.h index a04dbfd..a40ad63 100644 --- a/core/story-manager/src/nodes/connection.h +++ b/core/story-manager/src/nodes/connection.h @@ -29,23 +29,32 @@ struct Connection std::string inNodeId; unsigned int inPortIndex{0}; - Connection(const Connection &other){ - *this = other; + Connection(const Connection &other) + : type(other.type) + , outNodeId(other.outNodeId) + , outPortIndex(other.outPortIndex) + , inNodeId(other.inNodeId) + , inPortIndex(other.inPortIndex) + { + } Connection& operator=(const Connection& other) { - this->outNodeId = other.outNodeId; - this->outPortIndex = other.outPortIndex; - this->inNodeId = other.inNodeId; - this->inPortIndex = other.inPortIndex; + if (this != &other) { + this->outNodeId = other.outNodeId; + this->outPortIndex = other.outPortIndex; + this->inNodeId = other.inNodeId; + this->inPortIndex = other.inPortIndex; + this->type = other.type; + } return *this; - } + } }; inline bool operator==(Connection const &a, Connection const &b) { return a.outNodeId == b.outNodeId && a.outPortIndex == b.outPortIndex - && a.inNodeId == b.inNodeId && a.inPortIndex == b.inPortIndex; + && a.inNodeId == b.inNodeId && a.inPortIndex == b.inPortIndex && a.type == b.type; } inline bool operator!=(Connection const &a, Connection const &b) diff --git a/core/story-manager/src/nodes/print_node.h b/core/story-manager/src/nodes/print_node.h index 1bbab04..cc065e1 100644 --- a/core/story-manager/src/nodes/print_node.h +++ b/core/story-manager/src/nodes/print_node.h @@ -19,6 +19,14 @@ public: static constexpr int MAX_INPUT_COUNT = 4; + std::shared_ptr GetVariable(const std::string& label) const { + auto it = m_variables.find(label); + if (it != m_variables.end()) { + return it->second; + } + return nullptr; + } + private: std::string m_label; // Label for the string literal }; \ No newline at end of file diff --git a/core/story-manager/src/nodes/variable_node.cpp b/core/story-manager/src/nodes/variable_node.cpp index d9f0436..227ea04 100644 --- a/core/story-manager/src/nodes/variable_node.cpp +++ b/core/story-manager/src/nodes/variable_node.cpp @@ -45,4 +45,33 @@ void VariableNode::SetVariable(std::shared_ptr var) std::shared_ptr VariableNode::GetVariable() const { return m_variable; -} \ No newline at end of file +} + +bool VariableNode::ResolveVariable(const std::vector>& variables) +{ + // Si la variable est déjà résolue, pas besoin de chercher + if (m_variable) { + return true; + } + + // Si pas d'UUID, impossible de résoudre + if (m_variableUuid.empty()) { + std::cout << "WARNING: VariableNode " << GetId() + << " has no variable UUID!" << std::endl; + return false; + } + + // Chercher la variable correspondant à l'UUID + for (const auto& var : variables) { + if (var->GetUuid() == m_variableUuid) { + m_variable = var; + std::cout << "✓ Resolved variable '" << var->GetVariableName() + << "' for VariableNode " << GetId() << std::endl; + return true; + } + } + + std::cout << "ERROR: Could not resolve variable UUID " << m_variableUuid + << " for VariableNode " << GetId() << std::endl; + return false; +} diff --git a/core/story-manager/src/nodes/variable_node.h b/core/story-manager/src/nodes/variable_node.h index fcd7948..b739a06 100644 --- a/core/story-manager/src/nodes/variable_node.h +++ b/core/story-manager/src/nodes/variable_node.h @@ -20,6 +20,8 @@ public: void SetVariable(std::shared_ptr var); std::shared_ptr GetVariable() const; + bool ResolveVariable(const std::vector>& variables); + private: std::string m_variableUuid; std::shared_ptr m_variable; diff --git a/core/story-manager/src/story_project.cpp b/core/story-manager/src/story_project.cpp index a44372f..bcc75c8 100644 --- a/core/story-manager/src/story_project.cpp +++ b/core/story-manager/src/story_project.cpp @@ -436,8 +436,39 @@ bool StoryProject::GenerateCompleteProgram(std::string &assembly) // Stocker les données de chaque page pageData[std::string(page->Uuid())] = {pageNodes, pageLinks}; } + + std::cout << "\n=== Resolving VariableNode references ===\n"; + for (const auto& baseNode : allNodes) { + auto varNode = std::dynamic_pointer_cast(baseNode); + if (varNode) { + varNode->ResolveVariable(m_variables); + } + } - // === PHASE 2 : GÉNÉRATION === + // ✅ PHASE 2 : GÉNÉRATION DE TOUS LES TAC (avant la section DATA!) + std::cout << "\n=== Generating all TAC programs ===\n"; + std::map pageTACPrograms; + + for (const auto& page : m_pages) { + std::string pageUuid(page->Uuid()); + auto& [nodes, connections] = pageData[pageUuid]; + + // Construire l'AST pour cette page + ASTBuilder builder(nodes, connections); + auto astNodes = builder.BuildAST(); + + // Générer le TAC pour cette page + TACGenerator tacGen; + TACProgram pageTAC = tacGen.Generate(astNodes); + + // Stocker le TAC + pageTACPrograms[pageUuid] = pageTAC; + + std::cout << "Generated TAC for page: " << page->GetName() << std::endl; + } + std::cout << "=== All TAC programs generated ===\n\n"; + + // === PHASE 3 : GÉNÉRATION DE L'ASSEMBLEUR === AssemblyGenerator::GeneratorContext context( m_variables, "2025-01-10 15:30:00", @@ -453,13 +484,14 @@ bool StoryProject::GenerateCompleteProgram(std::string &assembly) generator.Reset(); generator.GenerateHeader(); - // === SECTION DATA (commune à toutes les pages) === + // === SECTION DATA (maintenant les format strings sont corrects!) === generator.StartSection(AssemblyGenerator::Section::DATA); // Variables globales (partagées entre toutes les pages) generator.GenerateGlobalVariables(); // Constantes de tous les nœuds de toutes les pages + // ✅ Les format strings ont déjà été modifiés par le TAC generator generator.GenerateNodesVariables(allNodes); // === SECTION TEXT (chaque page = une fonction) === @@ -469,11 +501,9 @@ bool StoryProject::GenerateCompleteProgram(std::string &assembly) bool isFirstPage = true; for (const auto& page : m_pages) { std::string pageUuid(page->Uuid()); - auto& [nodes, connections] = pageData[pageUuid]; - // Construire l'AST pour cette page - ASTBuilder builder(nodes, connections); - auto astNodes = builder.BuildAST(); + // Récupérer le TAC pré-généré + TACProgram& pageTAC = pageTACPrograms[pageUuid]; // Générer le label de fonction std::string functionLabel; @@ -490,10 +520,6 @@ bool StoryProject::GenerateCompleteProgram(std::string &assembly) generator.AddComment("========================================"); generator.GetAssembly() << functionLabel << ":\n"; - // Générer le TAC pour cette page - TACGenerator tacGen; - TACProgram pageTAC = tacGen.Generate(astNodes); - if (context.debugOutput) { std::cout << "\n=== TAC for page: " << page->GetName() << " ===\n"; std::cout << pageTAC.ToString() << std::endl; diff --git a/story-editor/imgui.ini b/story-editor/imgui.ini index 03d3205..22e98a7 100644 --- a/story-editor/imgui.ini +++ b/story-editor/imgui.ini @@ -1,6 +1,6 @@ [Window][WindowOverViewport_11111111] Pos=60,26 -Size=1220,694 +Size=1220,836 Collapsed=0 [Window][Debug##Default] @@ -10,31 +10,31 @@ Collapsed=0 [Window][Library Manager] Pos=630,26 -Size=650,235 +Size=650,518 Collapsed=0 DockId=0x00000002,0 [Window][Console] -Pos=60,263 -Size=628,457 +Pos=60,546 +Size=628,316 Collapsed=0 DockId=0x00000004,0 [Window][Emulator] Pos=630,26 -Size=650,235 +Size=650,518 Collapsed=0 DockId=0x00000002,5 [Window][Code viewer] Pos=630,26 -Size=650,235 +Size=650,518 Collapsed=0 DockId=0x00000002,4 [Window][Resources] Pos=630,26 -Size=650,235 +Size=650,518 Collapsed=0 DockId=0x00000002,1 @@ -50,36 +50,36 @@ Size=150,42 Collapsed=0 [Window][Variables] -Pos=690,263 -Size=590,457 +Pos=690,546 +Size=590,316 Collapsed=0 DockId=0x00000005,0 [Window][CPU] Pos=630,26 -Size=650,235 +Size=650,518 Collapsed=0 DockId=0x00000002,2 [Window][RAM view] Pos=630,26 -Size=650,235 +Size=650,518 Collapsed=0 DockId=0x00000002,3 [Window][Properties] -Pos=690,263 -Size=590,457 +Pos=690,546 +Size=590,316 Collapsed=0 DockId=0x00000005,1 [Window][ToolBar] Pos=0,26 -Size=60,694 +Size=60,836 Collapsed=0 [Window][QuitConfirm] -Pos=508,312 +Pos=508,383 Size=264,96 Collapsed=0 @@ -90,13 +90,13 @@ Collapsed=0 [Window][Module editor] Pos=60,26 -Size=568,235 +Size=568,518 Collapsed=0 DockId=0x00000001,0 [Window][Story editor] Pos=60,26 -Size=568,235 +Size=568,518 Collapsed=0 DockId=0x00000001,1 @@ -106,8 +106,8 @@ Size=687,422 Collapsed=0 [Window][Error List] -Pos=60,263 -Size=628,457 +Pos=60,546 +Size=628,316 Collapsed=0 DockId=0x00000004,1 @@ -155,11 +155,11 @@ Column 2 Weight=1.0000 Column 3 Width=60 [Docking][Data] -DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=60,26 Size=1220,694 Split=Y - DockNode ID=0x00000007 Parent=0x08BD597D SizeRef=1220,235 Split=X +DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=60,26 Size=1220,836 Split=Y + DockNode ID=0x00000007 Parent=0x08BD597D SizeRef=1220,549 Split=X DockNode ID=0x00000001 Parent=0x00000007 SizeRef=1144,694 CentralNode=1 Selected=0x93ADCAAB - DockNode ID=0x00000002 Parent=0x00000007 SizeRef=650,694 Selected=0x4B07C626 - DockNode ID=0x00000008 Parent=0x08BD597D SizeRef=1220,457 Split=X Selected=0xEA83D666 + DockNode ID=0x00000002 Parent=0x00000007 SizeRef=650,694 Selected=0xE5897A33 + DockNode ID=0x00000008 Parent=0x08BD597D SizeRef=1220,316 Split=X Selected=0xEA83D666 DockNode ID=0x00000004 Parent=0x00000008 SizeRef=616,192 Selected=0xEA83D666 DockNode ID=0x00000005 Parent=0x00000008 SizeRef=578,192 Selected=0x8C72BEA8 diff --git a/story-editor/src/app/app_controller.cpp b/story-editor/src/app/app_controller.cpp index e5ad8cf..fed942a 100644 --- a/story-editor/src/app/app_controller.cpp +++ b/story-editor/src/app/app_controller.cpp @@ -16,51 +16,7 @@ #include "variable.h" // Pour Variable #include "all_events.h" #include "Localization.h" - -// Définitions des registres et événements CHIP-32 si non déjà dans chip32_vm.h -#ifndef R0 -#define R0 0 -#endif -#ifndef R1 -#define R1 1 -#endif -#ifndef R2 -#define R2 2 -#endif -#ifndef R3 -#define R3 3 -#endif -#ifndef R4 -#define R4 4 -#endif -#ifndef PC -#define PC 7 // Exemple de registre Program Counter -#endif - -#ifndef EV_MASK_OK_BUTTON -#define EV_MASK_OK_BUTTON 1 -#endif -#ifndef EV_MASK_HOME_BUTTON -#define EV_MASK_HOME_BUTTON 2 -#endif -#ifndef EV_MASK_PREVIOUS_BUTTON -#define EV_MASK_PREVIOUS_BUTTON 4 -#endif -#ifndef EV_MASK_NEXT_BUTTON -#define EV_MASK_NEXT_BUTTON 8 -#endif -#ifndef EV_MASK_END_OF_AUDIO -#define EV_MASK_END_OF_AUDIO 16 -#endif - -// Définitions pour les codes de retour de Syscall -#ifndef SYSCALL_RET_OK -#define SYSCALL_RET_OK 0 -#endif -#ifndef SYSCALL_RET_WAIT_EV -#define SYSCALL_RET_WAIT_EV 1 // Exemple: VM doit attendre un événement -#endif - +#include "chip32_machine.h" AppController::AppController(ILogger& logger, EventBus& eventBus) : m_logger(logger) @@ -633,37 +589,6 @@ void AppController::LoadParams() } } -std::string AppController::GetStringFromMemory(uint32_t addr) -{ - // Buffer local pour la chaîne - // Assurez-vous qu'il est assez grand pour gérer les chaînes de votre VM - // et qu'il est terminé par null - char strBuf[256]; // Augmenté la taille pour plus de sécurité - - // Le bit le plus significatif indique si c'est de la RAM (0x80000000) ou ROM - bool isRam = (addr & 0x80000000) != 0; - addr &= 0xFFFF; // Masque pour obtenir l'adresse 16 bits - - // Vérification de l'adresse pour éviter les dépassements de buffer - if (isRam) { - if (addr < m_chip32_ctx.ram.size) { - strncpy(strBuf, (const char *)&m_chip32_ctx.ram.mem[addr], sizeof(strBuf) - 1); - strBuf[sizeof(strBuf) - 1] = '\0'; // S'assurer que c'est null-terminated - } else { - m_logger.Log("GetStringFromMemory: Invalid RAM address: 0x" + std::to_string(addr), true); - return ""; - } - } else { - if (addr < m_chip32_ctx.rom.size) { - strncpy(strBuf, (const char *)&m_chip32_ctx.rom.mem[addr], sizeof(strBuf) - 1); - strBuf[sizeof(strBuf) - 1] = '\0'; // S'assurer que c'est null-terminated - } else { - m_logger.Log("GetStringFromMemory: Invalid ROM address: 0x" + std::to_string(addr), true); - return ""; - } - } - return strBuf; -} void AppController::ProcessStory() { @@ -784,6 +709,7 @@ void AppController::StepInstruction() UpdateVmView(); } + uint8_t AppController::Syscall(chip32_ctx_t *ctx, uint8_t code) { uint8_t retCode = SYSCALL_RET_OK; @@ -795,7 +721,7 @@ uint8_t AppController::Syscall(chip32_ctx_t *ctx, uint8_t code) // R0: image file name address, R1: sound file name address if (ctx->registers[R0] != 0) { - std::string imageFile = m_story->BuildFullAssetsPath(GetStringFromMemory(ctx->registers[R0])); + std::string imageFile = m_story->BuildFullAssetsPath(Chip32::Machine::GetStringFromMemory(ctx, ctx->registers[R0])); m_logger.Log("Image: " + imageFile); // Ici, vous notifieriez la fenêtre de l'émulateur // m_emulatorDock.SetImage(imageFile); // Ceci est une dépendance GUI @@ -807,7 +733,7 @@ uint8_t AppController::Syscall(chip32_ctx_t *ctx, uint8_t code) if (ctx->registers[R1] != 0) { - std::string soundFile = m_story->BuildFullAssetsPath(GetStringFromMemory(ctx->registers[R1])); + std::string soundFile = m_story->BuildFullAssetsPath(Chip32::Machine::GetStringFromMemory(ctx, ctx->registers[R1])); m_logger.Log("Sound: " + soundFile); m_player.Play(soundFile); } @@ -827,23 +753,18 @@ uint8_t AppController::Syscall(chip32_ctx_t *ctx, uint8_t code) } else if (code == 4) // Printf (printf-like behavior) { - std::string text = GetStringFromMemory(ctx->registers[R0]); + std::string format = Chip32::Machine::GetStringFromMemory(ctx, ctx->registers[R0]); int arg_count = ctx->registers[R1]; - char working_buf[400] = {0}; - - // Simplified printf logic for logging - switch(arg_count){ - case 0: strcpy(working_buf, text.c_str()); break; - case 1: snprintf(working_buf, sizeof(working_buf), text.c_str(), ctx->registers[R2]); break; - case 2: snprintf(working_buf, sizeof(working_buf), text.c_str(), ctx->registers[R2], ctx->registers[R3]); break; - case 3: snprintf(working_buf, sizeof(working_buf), text.c_str(), ctx->registers[R2], ctx->registers[R3], ctx->registers[R4]); break; - default: m_logger.Log("Printf with unsupported arg_count: " + std::to_string(arg_count) + " text: " + text, true); break; + + std::vector args; + for (int i = 0; i < arg_count && i < 4; ++i) { + args.push_back(ctx->registers[R2 + i]); } // Send event to UI auto evObj = std::make_shared(); evObj->type = VmStateEvent::Type::PrintEvent; - evObj->printOutput = working_buf; + evObj->printOutput = Chip32::Machine::FormatStringWithPlaceholders(ctx, format, args); m_eventBus.Emit(evObj); } else if (code == 5) // WAIT (sleep) @@ -869,14 +790,13 @@ void AppController::UpdateVmView() // Au lieu de cela, il émettrait un signal ou appellerait un observer. uint32_t pcVal = m_chip32_ctx.registers[PC]; - if (m_story && m_story->GetAssemblyLine(pcVal, m_dbg.line)) + if (m_story) { - m_logger.Log("Executing line: " + std::to_string(m_dbg.line + 1)); + if (m_story->GetAssemblyLine(pcVal, m_dbg.line)) + { + m_logger.Log("Executing line: " + std::to_string(m_dbg.line + 1)); // m_debuggerWindow.HighlightLine(m_dbg.line); // Dépendance GUI - } - else - { - m_logger.Log("Reached end or instruction not found (line: " + std::to_string(m_dbg.line) + ")", false); + } } // m_cpuWindow.updateRegistersView(m_chip32_ctx); // Dépendance GUI // m_memoryEditor.DrawWindow("RAM view", m_chip32_ctx.ram.mem, m_chip32_ctx.ram.size); // Dépendance GUI diff --git a/story-editor/src/app/app_controller.h b/story-editor/src/app/app_controller.h index d8e9062..ee19f8a 100644 --- a/story-editor/src/app/app_controller.h +++ b/story-editor/src/app/app_controller.h @@ -100,7 +100,7 @@ public: // Méthodes pour interagir avec la VM et le débogueur chip32_ctx_t* GetChip32Context() { return &m_chip32_ctx; } DebugContext* GetDebugContext() { return &m_dbg; } - std::string GetStringFromMemory(uint32_t addr); + void ProcessStory(); void StepInstruction(); void StopAudio() { m_player.Stop(); } diff --git a/story-editor/src/main_window.cpp b/story-editor/src/main_window.cpp index d8c900b..18efedc 100644 --- a/story-editor/src/main_window.cpp +++ b/story-editor/src/main_window.cpp @@ -117,7 +117,7 @@ MainWindow::MainWindow(ILogger& logger, EventBus& eventBus, AppController& appCo // Show success message if no errors if (!m_errorListDock.HasErrors()) { // You can also open a popup if desired - m_logger.Log("✓ Module compilation successful - Binary saved and loaded into VM"); + m_logger.Log("Module compilation successful - Binary saved and loaded into VM"); } } else if (event.GetType() == ModuleEvent::Type::BuildFailure) { diff --git a/story-editor/src/node_editor/node_editor_page.h b/story-editor/src/node_editor/node_editor_page.h index b3d84a7..c6efe96 100644 --- a/story-editor/src/node_editor/node_editor_page.h +++ b/story-editor/src/node_editor/node_editor_page.h @@ -134,37 +134,6 @@ struct NodeEditorPage : public ImFlow::BaseNode return m_uuid; } - std::list> GetNodes() - { - std::list> nlist; - // std::unordered_map>& - for (auto &node : mINF.getNodes()) - { - auto delegate = dynamic_cast(node.second.get()); - - if (delegate == nullptr) - continue; - nlist.push_back(delegate->GetWidget()); - } - - return nlist; - } - - std::list> GetLinks() { - - std::list> links; - - // const std::vector>& getLinks() - for (auto &link : mINF.getLinks()) - { - auto linkInfo = std::make_shared(); - - links.push_back(linkInfo); - } - - return links; - } - void Select() { } diff --git a/story-editor/src/node_editor/node_editor_window.cpp b/story-editor/src/node_editor/node_editor_window.cpp index 8be1771..6bd66c2 100644 --- a/story-editor/src/node_editor/node_editor_window.cpp +++ b/story-editor/src/node_editor/node_editor_window.cpp @@ -379,6 +379,22 @@ void NodeEditorWindow::SaveNodesToProject() connection->inNodeId = rightBaseNode->GetId(); connection->inPortIndex = rightPinIndex; + // Detect type + auto outputPort = leftBaseNode->GetOutputPort(leftPinIndex); + if (outputPort.type == BaseNode::Port::Type::DATA_PORT) { + connection->type = Connection::DATA_LINK; + } else { + connection->type = Connection::EXECUTION_LINK; + } + +// // 🔍 DEBUG +// std::cout << "=== SAVE CONNECTION ===" << std::endl; +// std::cout << " From: " << connection->outNodeId << "[" << connection->outPortIndex << "]" << std::endl; +// std::cout << " To: " << connection->inNodeId << "[" << connection->inPortIndex << "]" << std::endl; +// std::cout << " Output port type: " << (outputPort.type == BaseNode::Port::Type::DATA_PORT ? "DATA_PORT" : "EXECUTION_PORT") << std::endl; +// std::cout << " Connection type: " << (connection->type == Connection::DATA_LINK ? "DATA_LINK" : "EXECUTION_LINK") << std::endl; +// std::cout << "========================" << std::endl; + // Add connection to project m_story->AddConnection(projectPage->Uuid(), connection); @@ -474,165 +490,15 @@ void NodeEditorWindow::Draw() ToolbarUI(); m_currentPage->Draw(m_nodesFactory, m_widgetFactory, m_manager); - - -/* - ed::Begin(m_currentPage->Uuid().data(), ImVec2(0.0, 0.0f)); - - // Draw our nodes - m_currentPage->Draw(); - - // Handle creation action, returns true if editor want to create new object (node or link) - if (ed::BeginCreate()) - { - ed::PinId startId, endId; - if (ed::QueryNewLink(&startId, &endId)) - { - // QueryNewLink returns true if editor want to create new link between pins. - // - // Link can be created only for two valid pins, it is up to you to - // validate if connection make sense. Editor is happy to make any. - // - // Link always goes from input to output. User may choose to drag - // link from output pin or input pin. This determine which pin ids - // are valid and which are not: - // * input valid, output invalid - user started to drag new ling from input pin - // * input invalid, output valid - user started to drag new ling from output pin - // * input valid, output valid - user dragged link over other pin, can be validated - - if (startId && endId) // both are valid, let's accept link - { - // ed::AcceptNewItem() return true when user release mouse button. - if (ed::AcceptNewItem()) - { - auto c = std::make_shared(); - - // On cherche à quel noeud appartien les pin (selon si le lien a été créé à partir d'une entrée ou d'une sortie) - if (FillConnection(c, startId)) - { - if (FillConnection(c, endId)) - { - m_story->AddConnection(m_currentPage->Uuid(), c); - - CreateLink(c, startId, endId); - - // Draw new link. - ed::Link(m_currentPage->m_links.back()->ed_link->Id, startId, endId); - } - } - } - - // You may choose to reject connection between these nodes - // by calling ed::RejectNewItem(). This will allow editor to give - // visual feedback by changing link thickness and color. - } - } - - ed::EndCreate(); // Wraps up object creation action handling. - } - - - - // Handle deletion action - if (ed::BeginDelete()) - { - ed::NodeId nodeId = 0; - while (ed::QueryDeletedNode(&nodeId)) - { - if (ed::AcceptDeletedItem()) - { - std::shared_ptr node; - if (m_currentPage->GetNode(nodeId, node)) - { - // First delete model, then current entry - m_story->DeleteNode(m_currentPage->Uuid(), node->Base()->GetId()); - m_currentPage->DeleteNode(nodeId); - } - } - } - - // There may be many links marked for deletion, let's loop over them. - ed::LinkId deletedLinkId; - while (ed::QueryDeletedLink(&deletedLinkId)) - { - // If you agree that link can be deleted, accept deletion. - if (ed::AcceptDeletedItem()) - { - std::shared_ptr model; - if (m_currentPage->GetModel(deletedLinkId, model)) - { - m_story->DeleteLink(m_currentPage->Uuid(), model); - m_currentPage->EraseLink(deletedLinkId); - } - } - - // You may reject link deletion by calling: - // ed::RejectDeletedItem(); - } - } - ed::EndDelete(); // Wrap up deletion action - - - auto openPopupPosition = ImGui::GetMousePos(); - ed::Suspend(); - - if (ed::ShowBackgroundContextMenu()) - { - ImGui::OpenPopup("Create New Node"); - } - - if (ImGui::BeginPopup("Create New Node")) - { - auto newNodePostion = openPopupPosition; - std::shared_ptr base; - auto nodeTypes = m_nodesFactory.ListOfNodes(); - - for (auto &type : nodeTypes) - { - if (ImGui::MenuItem(type.name.c_str())) - { - base = m_nodesFactory.CreateNode(type.uuid); - if (base) - { - m_story->AddNode(m_currentPage->Uuid(), base); - auto n = CreateNodeWidget(type.uuid, m_manager, base); - if (n) - { - n->Base()->SetPosition(newNodePostion.x, newNodePostion.y); - n->Initialize(); - m_currentPage->AddNode(n); - } - } - } - } - - ImGui::EndPopup(); - } - - if (m_loaded) - { - ed::NavigateToContent(); - m_loaded = false; - } - - ed::Resume(); - - - ed::End(); - ed::SetCurrentEditor(nullptr); - */ } else { // Set background color to light gray // ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0.7f, 0.7f, 0.7f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, 1.0f)); - ImGui::Text("Please load or create a project."); - ImGui::PopStyleColor(1); // Pop both colors } - } WindowBase::EndDraw(); @@ -640,16 +506,6 @@ void NodeEditorWindow::Draw() void NodeEditorWindow::ToolbarUI() { - // auto& io = ImGui::GetIO(); - // ImVec2 window_pos = ImGui::GetWindowPos(); - // ImVec2 window_size = ImGui::GetWindowSize(); - // ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoMove; - - // ImGui::SetNextWindowBgAlpha(0.35f); // Transparent background - - // ImGui::Begin("TOOLBAR", NULL, window_flags); - - ImGui::SetCursorPos(ImVec2(10, 40)); ImGui::BeginChild("ToolbarChild", ImVec2(0, ImGui::GetFrameHeightWithSpacing() * 1.5f), false, ImGuiWindowFlags_NoScrollbar); @@ -677,17 +533,7 @@ void NodeEditorWindow::ToolbarUI() ImGui::SameLine(); } - ImGui::PopID(); - - // ImGui::End(); - + ImGui::PopID(); ImGui::EndChild(); // Fin de la ChildWindow de la barre d'outils - ImGui::SetCursorPos(ImVec2(0, 0)); - - - // if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) - // { - // io.ConfigViewportsNoDecoration = false; - // } }