diff --git a/core/story-manager/interfaces/i_story_project.h b/core/story-manager/interfaces/i_story_project.h index e20edc3..f24cb8f 100644 --- a/core/story-manager/interfaces/i_story_project.h +++ b/core/story-manager/interfaces/i_story_project.h @@ -17,6 +17,11 @@ public: PROJECT_TYPE_PRIMITIVE = 2 }; + struct FunctionInfo { + std::string uuid; + std::string name; + }; + virtual ~IStoryProject() {}; virtual std::string GetName() const = 0; @@ -26,6 +31,7 @@ public: virtual std::string GetUuid() const = 0; virtual std::string GetTitleImage() const = 0; virtual std::string GetTitleSound() const = 0; + virtual std::vector GetFunctionsList() const = 0; virtual void SetTitleImage(const std::string &titleImage) = 0; virtual void SetTitleSound(const std::string &titleSound) = 0; diff --git a/core/story-manager/src/compiler/assembly_generator_chip32.h b/core/story-manager/src/compiler/assembly_generator_chip32.h index 24509bf..62ab485 100644 --- a/core/story-manager/src/compiler/assembly_generator_chip32.h +++ b/core/story-manager/src/compiler/assembly_generator_chip32.h @@ -2,12 +2,14 @@ #include "ast_builder.h" #include "assembly_generator.h" +#include "call_function_node.h" class AssemblyGeneratorChip32 : public AssemblyGenerator { public: AssemblyGeneratorChip32(const GeneratorContext& context) : AssemblyGenerator(context) + , m_currentContext(FunctionContext::MAIN_PROGRAM) { } @@ -28,6 +30,13 @@ public: GenerateOperatorNode(node); } else if (node->IsType()) { + // Détecter si c'est le main ou une sous-fonction + // Weight 100 = fonction principale (main) + auto* entry = node->GetAs(); + m_currentContext = (entry->GetWeight() >= 100) + ? FunctionContext::MAIN_PROGRAM + : FunctionContext::SUB_FUNCTION; + GenerateFunctionEntry(node); } else if (node->IsType()) { @@ -36,12 +45,20 @@ public: else if (node->IsType()) { GeneratePrintNode(node); } + else if (node->IsType()) { + GenerateCallFunctionNode(node); + } - // // If there is no any children, put an halt + // Détection automatique des fins de fonction/programme if (node->GetChildCount() == 0) { - AddComment("Program exit"); - m_assembly << " halt\n"; + if (m_currentContext == FunctionContext::MAIN_PROGRAM) { + AddComment("Program exit (automatic)"); + m_assembly << " halt\n"; + } else { + AddComment("Function return (automatic)"); + m_assembly << " ret\n"; + } } } @@ -55,6 +72,12 @@ public: } private: + enum class FunctionContext { + MAIN_PROGRAM, + SUB_FUNCTION + }; + + FunctionContext m_currentContext; virtual void GenerateMain() override { // Program entry point @@ -62,7 +85,39 @@ private: } void GenerateFunctionEntry(std::shared_ptr node) { - AddComment("Function Entry"); + auto* entry = node->GetAs(); + + if (m_currentContext == FunctionContext::MAIN_PROGRAM) { + AddComment("Main function entry"); + } else { + AddComment("Function entry"); + // Si nécessaire, sauvegarder les registres + // m_assembly << " push r0\n"; + // m_assembly << " push r1\n"; + // etc. + } + } + + void GenerateCallFunctionNode(std::shared_ptr node) { + auto* callNode = node->GetAs(); + if (!callNode) return; + + std::string functionName = callNode->GetFunctionName(); + + AddComment("Call function: " + functionName); + m_depth++; + + // Préparer les arguments si nécessaire + // Dans votre système, les variables globales sont utilisées + // donc pas besoin de passer des arguments sur la pile + + // Appel de la fonction + m_assembly << " call " << GetFunctionLabel(functionName) << "\n"; + + // Après le retour de la fonction, les variables globales + // ont potentiellement été modifiées et sont directement accessibles + + m_depth--; } void GenerateBranchNode(std::shared_ptr node) @@ -88,24 +143,20 @@ private: std::string label = printNode->GetLabel(); - - m_assembly << " push r0\n" - << " push r1\n" - << " lcons r0, $" << label << "\n" - << " lcons r1, 0 ; number of arguments\n" // FIXME: handle arguments - << " syscall 4\n" - << " pop r1\n" - << " pop r0\n"; - -// << ""mov r2, %2 // arguments are in r2, r3, r4 etc. - + m_assembly << " push r0\n" + << " push r1\n" + << " lcons r0, $" << label << "\n" + << " lcons r1, 0 ; number of arguments\n" // FIXME: handle arguments + << " syscall 4\n" + << " pop r1\n" + << " pop r0\n"; } void GenerateOperatorNode(std::shared_ptr node) { auto* opNode = node->GetAs(); if (!opNode) return; - AddComment("Operator: " + std::to_string(static_cast(opNode->GetOperationType()))); + AddComment("Operator: " + opNode->GetOperatorSymbol()); m_depth++; // Generate code for variables usage @@ -125,7 +176,7 @@ private: { // Generate code to load the variable value // FIXME: hardcoded 4 bytes, replace by actual real variable size - m_assembly << " load r" << reg << ", $" << var->GetLabel() << ", 4" << "; Load variable " << var->GetVariableName() << "\n"; + m_assembly << " load r" << reg << ", $" << var->GetLabel() << ", 4" << " ; Load variable " << var->GetVariableName() << "\n"; m_assembly << " push r" << reg << "\n"; } else @@ -135,13 +186,9 @@ private: } reg++; } - - - // m_assembly << " load r0, " << inputNode.node->GetId() << "\n"; } - - // Generate operator code + // Generate operator code based on type switch (opNode->GetOperationType()) { case OperatorNode::OperationType::ADD: m_assembly << " pop r0\n" @@ -167,28 +214,133 @@ private: << " div r0, r1\n" << " push r0\n"; break; + case OperatorNode::OperationType::MODULO: + m_assembly << " pop r0\n" + << " pop r1\n" + << " mod r0, r1\n" + << " push r0\n"; + break; + case OperatorNode::OperationType::EQUAL: + m_assembly << " pop r0\n" + << " pop r1\n" + << " cmp r0, r1\n" + << " lcons r0, 1\n" + << " skipz\n" + << " lcons r0, 0\n" + << " push r0\n"; + break; + case OperatorNode::OperationType::NOT_EQUAL: + m_assembly << " pop r0\n" + << " pop r1\n" + << " cmp r0, r1\n" + << " lcons r0, 0\n" + << " skipz\n" + << " lcons r0, 1\n" + << " push r0\n"; + break; + case OperatorNode::OperationType::GREATER_THAN: + m_assembly << " pop r0\n" + << " pop r1\n" + << " cmp r0, r1\n" + << " lcons r0, 1\n" + << " skipgt\n" + << " lcons r0, 0\n" + << " push r0\n"; + break; + case OperatorNode::OperationType::LESS_THAN: + m_assembly << " pop r0\n" + << " pop r1\n" + << " cmp r0, r1\n" + << " lcons r0, 1\n" + << " skiplt\n" + << " lcons r0, 0\n" + << " push r0\n"; + break; + case OperatorNode::OperationType::GREATER_EQUAL: + m_assembly << " pop r0\n" + << " pop r1\n" + << " cmp r0, r1\n" + << " lcons r0, 1\n" + << " skipge\n" + << " lcons r0, 0\n" + << " push r0\n"; + break; + case OperatorNode::OperationType::LESS_EQUAL: + m_assembly << " pop r0\n" + << " pop r1\n" + << " cmp r0, r1\n" + << " lcons r0, 1\n" + << " skiple\n" + << " lcons r0, 0\n" + << " push r0\n"; + break; case OperatorNode::OperationType::AND: m_assembly << " pop r0\n" << " pop r1\n" << " and r0, r1\n" << " push r0\n"; break; - case OperatorNode::OperationType::GREATER_THAN: + case OperatorNode::OperationType::OR: m_assembly << " pop r0\n" << " pop r1\n" - << " gt r0, r0, r1\n" + << " or r0, r1\n" + << " push r0\n"; + break; + case OperatorNode::OperationType::NOT: + m_assembly << " pop r0\n" + << " not r0\n" + << " push r0\n"; + break; + case OperatorNode::OperationType::BITWISE_AND: + m_assembly << " pop r0\n" + << " pop r1\n" + << " and r0, r1\n" + << " push r0\n"; + break; + case OperatorNode::OperationType::BITWISE_OR: + m_assembly << " pop r0\n" + << " pop r1\n" + << " or r0, r1\n" + << " push r0\n"; + break; + case OperatorNode::OperationType::BITWISE_XOR: + m_assembly << " pop r0\n" + << " pop r1\n" + << " xor r0, r1\n" + << " push r0\n"; + break; + case OperatorNode::OperationType::BITWISE_NOT: + m_assembly << " pop r0\n" + << " not r0\n" + << " push r0\n"; + break; + case OperatorNode::OperationType::LEFT_SHIFT: + m_assembly << " pop r0\n" + << " pop r1\n" + << " shl r0, r1\n" + << " push r0\n"; + break; + case OperatorNode::OperationType::RIGHT_SHIFT: + m_assembly << " pop r0\n" + << " pop r1\n" + << " shr r0, r1\n" << " push r0\n"; break; default: - // Make voluntary bad assembly - m_assembly << "------>>>> OPERATOR NOT IMPLEMENTED: " << opNode->GetOperatorSymbol() << "\n"; - break; + throw std::runtime_error("Unsupported operator type"); } m_depth--; } - virtual void Visit(const std::shared_ptr v) override + // Helper pour générer le label d'une fonction à partir de son nom + std::string GetFunctionLabel(const std::string& functionName) { + // Convertir le nom de fonction en label valide + // Par exemple: "MyFunction" -> ".func_MyFunction" + return ".func_" + functionName; + } + + virtual void Visit(const std::shared_ptr v) override { if (v->IsConstant()) { @@ -232,7 +384,4 @@ private: m_assembly << "$" << v->GetLabel() << " DVB, " << (v->GetValue() ? "1" : "0") << " ; " << v->GetVariableName() << "\n"; } } - -}; - - +}; \ No newline at end of file diff --git a/core/story-manager/src/nodes/base_node.h b/core/story-manager/src/nodes/base_node.h index 0f18ea8..dc90e7a 100644 --- a/core/story-manager/src/nodes/base_node.h +++ b/core/story-manager/src/nodes/base_node.h @@ -102,6 +102,22 @@ public: return m_weight; } + void SetupExecutionPorts(bool hasInput = true, + int numOutputs = 1, + bool customRendering = true) + { + if (m_behavior != BEHAVIOR_EXECUTION) return; + + if (hasInput) { + AddInputPort(Port::Type::EXECUTION_PORT, ">", customRendering); + } + + for (int i = 0; i < numOutputs; ++i) { + std::string label = (numOutputs == 1) ? ">" : std::to_string(i); + AddOutputPort(Port::Type::EXECUTION_PORT, label, customRendering); + } + } + void SetId(const std::string &id) { m_uuid = id; } std::string GetId() const { return m_uuid; } @@ -121,8 +137,8 @@ public: } // Port management - void AddInputPort(Port::Type type, const std::string& label) { - m_inputPorts.push_back({type, label}); + void AddInputPort(Port::Type type, const std::string& label, bool customRendering = false) { + m_inputPorts.push_back({type, label, customRendering}); } void AddOutputPort(Port::Type type, const std::string& label, bool customRendering = false) { diff --git a/core/story-manager/src/nodes/call_function_node.cpp b/core/story-manager/src/nodes/call_function_node.cpp deleted file mode 100644 index 7601686..0000000 --- a/core/story-manager/src/nodes/call_function_node.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "call_function_node.h" -#include "story_project.h" -#include "connection.h" -#include "sys_lib.h" - - -CallFunctionNode::CallFunctionNode(const std::string &type) - : BaseNode(type, "Call Function Node") -{ - nlohmann::json j{ {"function", ""} }; - SetInternalData(j); -} - -void CallFunctionNode::Initialize() -{ - nlohmann::json j = GetInternalData(); - // m_image = j["image"].get(); - // m_sound = j["sound"].get(); -} - diff --git a/core/story-manager/src/nodes/call_function_node.h b/core/story-manager/src/nodes/call_function_node.h index 9a5c6fd..989f86d 100644 --- a/core/story-manager/src/nodes/call_function_node.h +++ b/core/story-manager/src/nodes/call_function_node.h @@ -1,19 +1,51 @@ +// call_function_node.h #pragma once -#include -#include "i_story_manager.h" #include "base_node.h" -#include "i_script_node.h" -#include "i_story_project.h" class CallFunctionNode : public BaseNode { public: - CallFunctionNode(const std::string &type); + CallFunctionNode(const std::string &type) + : BaseNode(type, "Call Function Node") + , m_functionName("") + , m_functionUuid("") + { + SetBehavior(BaseNode::BEHAVIOR_EXECUTION); + SetupExecutionPorts(true, 1, true); // 1 entrée, 1 sortie + } - virtual void Initialize() override; + void Initialize() override { + // Charger le nom et l'UUID de la fonction depuis les données internes + nlohmann::json j = GetInternalData(); + if (j.contains("functionName")) { + m_functionName = j["functionName"].get(); + } + if (j.contains("functionUuid")) { + m_functionUuid = j["functionUuid"].get(); + } + } + + std::string GetFunctionName() const { + return m_functionName; + } + + std::string GetFunctionUuid() const { + return m_functionUuid; + } + + void SetFunction(const std::string& uuid, const std::string& name) { + m_functionUuid = uuid; + m_functionName = name; + + // Sauvegarder dans les données internes pour la persistance + nlohmann::json j; + j["functionName"] = m_functionName; + j["functionUuid"] = m_functionUuid; + SetInternalData(j); + } private: - nlohmann::json m_content; -}; - + std::string m_functionName; + std::string m_functionUuid; +}; \ No newline at end of file diff --git a/core/story-manager/src/nodes/function_entry_node.h b/core/story-manager/src/nodes/function_entry_node.h index 89fa575..2676104 100644 --- a/core/story-manager/src/nodes/function_entry_node.h +++ b/core/story-manager/src/nodes/function_entry_node.h @@ -11,7 +11,7 @@ public: { SetWeight(100); SetBehavior(BaseNode::BEHAVIOR_EXECUTION); - AddOutputPort(BaseNode::Port::Type::EXECUTION_PORT, ">", true); + SetupExecutionPorts(false, 1, true); } void Initialize() override { diff --git a/core/story-manager/src/nodes/function_exit_node.h b/core/story-manager/src/nodes/function_exit_node.h deleted file mode 100644 index 8cf2dcb..0000000 --- a/core/story-manager/src/nodes/function_exit_node.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include "base_node.h" - -class FunctionExitNode : public BaseNode -{ -public: - FunctionExitNode(const std::string &type) - : BaseNode(type, "Function Exit Node") - { - - SetBehavior(BaseNode::BEHAVIOR_EXECUTION); - } - - void Initialize() override { - // Initialisation spécifique pour FunctionExitNode - // Par exemple, préparer les sorties nécessaires pour la fonction - } - - - - // Ajoutez des méthodes spécifiques pour gérer la sortie de la fonction - void FinalizeFunctionExit() { - // Logique pour finaliser la sortie de la fonction - } -}; diff --git a/core/story-manager/src/nodes/print_node.cpp b/core/story-manager/src/nodes/print_node.cpp index 324b395..06e394f 100644 --- a/core/story-manager/src/nodes/print_node.cpp +++ b/core/story-manager/src/nodes/print_node.cpp @@ -14,18 +14,13 @@ PrintNode::PrintNode(const std::string &type) m_variables[m_label] = v; SetBehavior(BaseNode::BEHAVIOR_EXECUTION); - - // Add execution input port (sync) - AddInputPort(Port::EXECUTION_PORT, ">"); + SetupExecutionPorts(true, 1, true); // Add 4 data input ports for arguments for (int i = 0; i < MAX_INPUT_COUNT; ++i) { AddInputPort(Port::DATA_PORT, "arg" + std::to_string(i)); } - - // Add execution output port - AddOutputPort(Port::EXECUTION_PORT, ">"); - + SetText(""); } diff --git a/core/story-manager/src/nodes_factory.h b/core/story-manager/src/nodes_factory.h index cececdc..d59e92f 100644 --- a/core/story-manager/src/nodes_factory.h +++ b/core/story-manager/src/nodes_factory.h @@ -16,7 +16,7 @@ #include "story_project.h" #include "story_primitive.h" #include "function_entry_node.h" -#include "function_exit_node.h" + static const std::string OperatorNodeUuid = "0226fdac-8f7a-47d7-8584-b23aceb712ec"; 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 SyscallNodeUuid = "02225cff-4975-400e-8130-41524d8af773"; static const std::string FunctionEntryNodeUuid = "02fd145a-b3a6-43c2-83ce-6a187e6d4b5b"; -static const std::string FunctionExitNodeUuid = "027b723d-2327-4646-a17a-79ddc2e016e4"; +static const std::string DUMMY_a_prendre_Uuid = "027b723d-2327-4646-a17a-79ddc2e016e4"; typedef std::shared_ptr (*GenericCreator)(const std::string &type); @@ -44,7 +44,6 @@ public: registerNode(PrintNodeUuid, std::make_shared("Print")); registerNode(SyscallNodeUuid, std::make_shared("System call")); registerNode(FunctionEntryNodeUuid, std::make_shared("Function entry")); - registerNode(FunctionExitNodeUuid, std::make_shared("Function exit")); } ~NodesFactory() = default; diff --git a/core/story-manager/src/story_page.h b/core/story-manager/src/story_page.h index 180beff..1622968 100644 --- a/core/story-manager/src/story_page.h +++ b/core/story-manager/src/story_page.h @@ -16,6 +16,7 @@ class StoryPage : public IStoryPage public: StoryPage(const std::string_view uuid) : m_uuid(uuid) + , m_name("Unnamed Page") { } ~StoryPage() { @@ -26,6 +27,9 @@ public: std::string_view Uuid() const { return m_uuid; } + std::string_view GetName() const { return m_name; } + void SetName(const std::string& name) { m_name = name; } + void AddNode(std::shared_ptr node) { m_nodes.push_back(node); } @@ -125,6 +129,7 @@ public: { nlohmann::json model; model["uuid"] = m_uuid; + model["name"] = m_name; nlohmann::json nodes = nlohmann::json::array(); for (const auto & n : m_nodes) diff --git a/core/story-manager/src/story_primitive.h b/core/story-manager/src/story_primitive.h index 1e388b2..47a9ff2 100644 --- a/core/story-manager/src/story_primitive.h +++ b/core/story-manager/src/story_primitive.h @@ -36,6 +36,9 @@ public: return m_uuid; } + virtual std::vector GetFunctionsList() const override { + return std::vector(); + } virtual std::string GetTitleImage() const { diff --git a/core/story-manager/src/story_project.cpp b/core/story-manager/src/story_project.cpp index 6e5a39d..7c75ce3 100644 --- a/core/story-manager/src/story_project.cpp +++ b/core/story-manager/src/story_project.cpp @@ -268,6 +268,7 @@ bool StoryProject::ModelFromJson(const nlohmann::json &model, NodesFactory &fact // 1. Create the page in memory auto p = std::make_shared(pageModel["uuid"].get()); m_pages.push_back(p); + p->SetName(pageModel.value("name", "Unnamed Page")); // 2. Load the nodes nlohmann::json nodesJsonArray = pageModel["nodes"]; @@ -332,6 +333,30 @@ bool StoryProject::CopyProgramTo(uint8_t *memory, uint32_t size) return success; } +std::vector StoryProject::GetFunctionsList() const +{ + std::vector functions; + + // Parcourir toutes les pages du projet + for (const auto& page : m_pages) + { + // Exclure la page main (MainUuid) + if (page->Uuid() == MainUuid()) + { + continue; + } + + // Ajouter la page à la liste des fonctions disponibles + IStoryProject::FunctionInfo info; + info.uuid = page->Uuid(); + info.name = page->GetName(); + + functions.push_back(info); + } + + return functions; +} + bool StoryProject::GetAssemblyLine(uint32_t pointer_counter, uint32_t &line) { bool success = false; diff --git a/core/story-manager/src/story_project.h b/core/story-manager/src/story_project.h index a4247a6..f52c55d 100644 --- a/core/story-manager/src/story_project.h +++ b/core/story-manager/src/story_project.h @@ -99,6 +99,7 @@ public: virtual void SetName(const std::string &name) override { m_name = name; } virtual void SetUuid(const std::string &uuid) override { m_uuid = uuid; } virtual Type GetProjectType() const override { return m_projectType; } + std::vector GetFunctionsList() const override; // Node interaction std::shared_ptr CreatePage(const std::string_view uuid);