removed exit node, nex function widget

This commit is contained in:
anthony@rabine.fr 2025-10-02 17:41:42 +02:00
parent 3e00fb1c83
commit 6d544f5879
13 changed files with 285 additions and 100 deletions

View file

@ -17,6 +17,11 @@ public:
PROJECT_TYPE_PRIMITIVE = 2 PROJECT_TYPE_PRIMITIVE = 2
}; };
struct FunctionInfo {
std::string uuid;
std::string name;
};
virtual ~IStoryProject() {}; virtual ~IStoryProject() {};
virtual std::string GetName() const = 0; virtual std::string GetName() const = 0;
@ -26,6 +31,7 @@ public:
virtual std::string GetUuid() const = 0; virtual std::string GetUuid() const = 0;
virtual std::string GetTitleImage() const = 0; virtual std::string GetTitleImage() const = 0;
virtual std::string GetTitleSound() const = 0; virtual std::string GetTitleSound() const = 0;
virtual std::vector<FunctionInfo> GetFunctionsList() const = 0;
virtual void SetTitleImage(const std::string &titleImage) = 0; virtual void SetTitleImage(const std::string &titleImage) = 0;
virtual void SetTitleSound(const std::string &titleSound) = 0; virtual void SetTitleSound(const std::string &titleSound) = 0;

View file

@ -2,12 +2,14 @@
#include "ast_builder.h" #include "ast_builder.h"
#include "assembly_generator.h" #include "assembly_generator.h"
#include "call_function_node.h"
class AssemblyGeneratorChip32 : public AssemblyGenerator class AssemblyGeneratorChip32 : public AssemblyGenerator
{ {
public: public:
AssemblyGeneratorChip32(const GeneratorContext& context) AssemblyGeneratorChip32(const GeneratorContext& context)
: AssemblyGenerator(context) : AssemblyGenerator(context)
, m_currentContext(FunctionContext::MAIN_PROGRAM)
{ {
} }
@ -28,6 +30,13 @@ public:
GenerateOperatorNode(node); GenerateOperatorNode(node);
} }
else if (node->IsType<FunctionEntryNode>()) { else if (node->IsType<FunctionEntryNode>()) {
// Détecter si c'est le main ou une sous-fonction
// Weight 100 = fonction principale (main)
auto* entry = node->GetAs<FunctionEntryNode>();
m_currentContext = (entry->GetWeight() >= 100)
? FunctionContext::MAIN_PROGRAM
: FunctionContext::SUB_FUNCTION;
GenerateFunctionEntry(node); GenerateFunctionEntry(node);
} }
else if (node->IsType<BranchNode>()) { else if (node->IsType<BranchNode>()) {
@ -36,12 +45,20 @@ public:
else if (node->IsType<PrintNode>()) { else if (node->IsType<PrintNode>()) {
GeneratePrintNode(node); GeneratePrintNode(node);
} }
else if (node->IsType<CallFunctionNode>()) {
GenerateCallFunctionNode(node);
}
// // If there is no any children, put an halt // Détection automatique des fins de fonction/programme
if (node->GetChildCount() == 0) if (node->GetChildCount() == 0)
{ {
AddComment("Program exit"); if (m_currentContext == FunctionContext::MAIN_PROGRAM) {
m_assembly << " halt\n"; AddComment("Program exit (automatic)");
m_assembly << " halt\n";
} else {
AddComment("Function return (automatic)");
m_assembly << " ret\n";
}
} }
} }
@ -55,6 +72,12 @@ public:
} }
private: private:
enum class FunctionContext {
MAIN_PROGRAM,
SUB_FUNCTION
};
FunctionContext m_currentContext;
virtual void GenerateMain() override { virtual void GenerateMain() override {
// Program entry point // Program entry point
@ -62,7 +85,39 @@ private:
} }
void GenerateFunctionEntry(std::shared_ptr<ASTNode> node) { void GenerateFunctionEntry(std::shared_ptr<ASTNode> node) {
AddComment("Function Entry"); auto* entry = node->GetAs<FunctionEntryNode>();
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<ASTNode> node) {
auto* callNode = node->GetAs<CallFunctionNode>();
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<ASTNode> node) void GenerateBranchNode(std::shared_ptr<ASTNode> node)
@ -88,24 +143,20 @@ private:
std::string label = printNode->GetLabel(); std::string label = printNode->GetLabel();
m_assembly << " push r0\n"
m_assembly << " push r0\n" << " push r1\n"
<< " push r1\n" << " lcons r0, $" << label << "\n"
<< " lcons r0, $" << label << "\n" << " lcons r1, 0 ; number of arguments\n" // FIXME: handle arguments
<< " lcons r1, 0 ; number of arguments\n" // FIXME: handle arguments << " syscall 4\n"
<< " syscall 4\n" << " pop r1\n"
<< " pop r1\n" << " pop r0\n";
<< " pop r0\n";
// << ""mov r2, %2 // arguments are in r2, r3, r4 etc.
} }
void GenerateOperatorNode(std::shared_ptr<ASTNode> node) { void GenerateOperatorNode(std::shared_ptr<ASTNode> node) {
auto* opNode = node->GetAs<OperatorNode>(); auto* opNode = node->GetAs<OperatorNode>();
if (!opNode) return; if (!opNode) return;
AddComment("Operator: " + std::to_string(static_cast<int>(opNode->GetOperationType()))); AddComment("Operator: " + opNode->GetOperatorSymbol());
m_depth++; m_depth++;
// Generate code for variables usage // Generate code for variables usage
@ -125,7 +176,7 @@ private:
{ {
// Generate code to load the variable value // Generate code to load the variable value
// FIXME: hardcoded 4 bytes, replace by actual real variable size // 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"; m_assembly << " push r" << reg << "\n";
} }
else else
@ -135,13 +186,9 @@ private:
} }
reg++; reg++;
} }
// m_assembly << " load r0, " << inputNode.node->GetId() << "\n";
} }
// Generate operator code based on type
// Generate operator code
switch (opNode->GetOperationType()) { switch (opNode->GetOperationType()) {
case OperatorNode::OperationType::ADD: case OperatorNode::OperationType::ADD:
m_assembly << " pop r0\n" m_assembly << " pop r0\n"
@ -167,28 +214,133 @@ private:
<< " div r0, r1\n" << " div r0, r1\n"
<< " push r0\n"; << " push r0\n";
break; 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: case OperatorNode::OperationType::AND:
m_assembly << " pop r0\n" m_assembly << " pop r0\n"
<< " pop r1\n" << " pop r1\n"
<< " and r0, r1\n" << " and r0, r1\n"
<< " push r0\n"; << " push r0\n";
break; break;
case OperatorNode::OperationType::GREATER_THAN: case OperatorNode::OperationType::OR:
m_assembly << " pop r0\n" m_assembly << " pop r0\n"
<< " pop r1\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"; << " push r0\n";
break; break;
default: default:
// Make voluntary bad assembly throw std::runtime_error("Unsupported operator type");
m_assembly << "------>>>> OPERATOR NOT IMPLEMENTED: " << opNode->GetOperatorSymbol() << "\n";
break;
} }
m_depth--; m_depth--;
} }
virtual void Visit(const std::shared_ptr<Variable> 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<Variable> v) override
{ {
if (v->IsConstant()) if (v->IsConstant())
{ {
@ -232,7 +384,4 @@ private:
m_assembly << "$" << v->GetLabel() << " DVB, " << (v->GetValue<bool>() ? "1" : "0") << " ; " << v->GetVariableName() << "\n"; m_assembly << "$" << v->GetLabel() << " DVB, " << (v->GetValue<bool>() ? "1" : "0") << " ; " << v->GetVariableName() << "\n";
} }
} }
};
};

View file

@ -102,6 +102,22 @@ public:
return m_weight; 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; } void SetId(const std::string &id) { m_uuid = id; }
std::string GetId() const { return m_uuid; } std::string GetId() const { return m_uuid; }
@ -121,8 +137,8 @@ public:
} }
// Port management // Port management
void AddInputPort(Port::Type type, const std::string& label) { void AddInputPort(Port::Type type, const std::string& label, bool customRendering = false) {
m_inputPorts.push_back({type, label}); m_inputPorts.push_back({type, label, customRendering});
} }
void AddOutputPort(Port::Type type, const std::string& label, bool customRendering = false) { void AddOutputPort(Port::Type type, const std::string& label, bool customRendering = false) {

View file

@ -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<std::string>();
// m_sound = j["sound"].get<std::string>();
}

View file

@ -1,19 +1,51 @@
// call_function_node.h
#pragma once #pragma once
#include <string>
#include "i_story_manager.h"
#include "base_node.h" #include "base_node.h"
#include "i_script_node.h"
#include "i_story_project.h"
class CallFunctionNode : public BaseNode class CallFunctionNode : public BaseNode
{ {
public: 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<std::string>();
}
if (j.contains("functionUuid")) {
m_functionUuid = j["functionUuid"].get<std::string>();
}
}
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: private:
nlohmann::json m_content; std::string m_functionName;
}; std::string m_functionUuid;
};

View file

@ -11,7 +11,7 @@ public:
{ {
SetWeight(100); SetWeight(100);
SetBehavior(BaseNode::BEHAVIOR_EXECUTION); SetBehavior(BaseNode::BEHAVIOR_EXECUTION);
AddOutputPort(BaseNode::Port::Type::EXECUTION_PORT, ">", true); SetupExecutionPorts(false, 1, true);
} }
void Initialize() override { void Initialize() override {

View file

@ -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
}
};

View file

@ -14,18 +14,13 @@ PrintNode::PrintNode(const std::string &type)
m_variables[m_label] = v; m_variables[m_label] = v;
SetBehavior(BaseNode::BEHAVIOR_EXECUTION); SetBehavior(BaseNode::BEHAVIOR_EXECUTION);
SetupExecutionPorts(true, 1, true);
// Add execution input port (sync)
AddInputPort(Port::EXECUTION_PORT, ">");
// Add 4 data input ports for arguments // Add 4 data input ports for arguments
for (int i = 0; i < MAX_INPUT_COUNT; ++i) { for (int i = 0; i < MAX_INPUT_COUNT; ++i) {
AddInputPort(Port::DATA_PORT, "arg" + std::to_string(i)); AddInputPort(Port::DATA_PORT, "arg" + std::to_string(i));
} }
// Add execution output port
AddOutputPort(Port::EXECUTION_PORT, ">");
SetText(""); SetText("");
} }

View file

@ -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 "function_exit_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 FunctionExitNodeUuid = "027b723d-2327-4646-a17a-79ddc2e016e4"; static const std::string DUMMY_a_prendre_Uuid = "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,7 +44,6 @@ 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<FunctionExitNode>(FunctionExitNodeUuid, std::make_shared<StoryPrimitive>("Function exit"));
} }
~NodesFactory() = default; ~NodesFactory() = default;

View file

@ -16,6 +16,7 @@ class StoryPage : public IStoryPage
public: public:
StoryPage(const std::string_view uuid) StoryPage(const std::string_view uuid)
: m_uuid(uuid) : m_uuid(uuid)
, m_name("Unnamed Page")
{ {
} }
~StoryPage() { ~StoryPage() {
@ -26,6 +27,9 @@ public:
std::string_view Uuid() const { return m_uuid; } 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<BaseNode> node) { void AddNode(std::shared_ptr<BaseNode> node) {
m_nodes.push_back(node); m_nodes.push_back(node);
} }
@ -125,6 +129,7 @@ public:
{ {
nlohmann::json model; nlohmann::json model;
model["uuid"] = m_uuid; model["uuid"] = m_uuid;
model["name"] = m_name;
nlohmann::json nodes = nlohmann::json::array(); nlohmann::json nodes = nlohmann::json::array();
for (const auto & n : m_nodes) for (const auto & n : m_nodes)

View file

@ -36,6 +36,9 @@ public:
return m_uuid; return m_uuid;
} }
virtual std::vector<FunctionInfo> GetFunctionsList() const override {
return std::vector<FunctionInfo>();
}
virtual std::string GetTitleImage() const { virtual std::string GetTitleImage() const {

View file

@ -268,6 +268,7 @@ bool StoryProject::ModelFromJson(const nlohmann::json &model, NodesFactory &fact
// 1. Create the page in memory // 1. Create the page in memory
auto p = std::make_shared<StoryPage>(pageModel["uuid"].get<std::string>()); auto p = std::make_shared<StoryPage>(pageModel["uuid"].get<std::string>());
m_pages.push_back(p); m_pages.push_back(p);
p->SetName(pageModel.value("name", "Unnamed Page"));
// 2. Load the nodes // 2. Load the nodes
nlohmann::json nodesJsonArray = pageModel["nodes"]; nlohmann::json nodesJsonArray = pageModel["nodes"];
@ -332,6 +333,30 @@ bool StoryProject::CopyProgramTo(uint8_t *memory, uint32_t size)
return success; return success;
} }
std::vector<IStoryProject::FunctionInfo> StoryProject::GetFunctionsList() const
{
std::vector<IStoryProject::FunctionInfo> 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 StoryProject::GetAssemblyLine(uint32_t pointer_counter, uint32_t &line)
{ {
bool success = false; bool success = false;

View file

@ -99,6 +99,7 @@ public:
virtual void SetName(const std::string &name) override { m_name = name; } virtual void SetName(const std::string &name) override { m_name = name; }
virtual void SetUuid(const std::string &uuid) override { m_uuid = uuid; } virtual void SetUuid(const std::string &uuid) override { m_uuid = uuid; }
virtual Type GetProjectType() const override { return m_projectType; } virtual Type GetProjectType() const override { return m_projectType; }
std::vector<FunctionInfo> GetFunctionsList() const override;
// Node interaction // Node interaction
std::shared_ptr<StoryPage> CreatePage(const std::string_view uuid); std::shared_ptr<StoryPage> CreatePage(const std::string_view uuid);