From 666e395002dc3d5ce17614f8ab2eb66a47ee5470 Mon Sep 17 00:00:00 2001
From: vl241552 <vincent.lorrain@cea.fr>
Date: Tue, 25 Jul 2023 09:06:11 +0000
Subject: [PATCH] Add the new POC for nodeTest using a string expression and
 lambda registry

---
 .../include/nodeTester/ConditionalData.hpp    | 137 +++++++
 .../nodeTester/ConditionalInterpreter.hpp     | 291 ++++++++++++++
 .../include/nodeTester/ConditionalLexer.hpp   | 153 ++++++++
 .../include/nodeTester/ConditionalParser.hpp  | 116 ++++++
 .../src/nodeTester/ConditionalInterpreter.cpp | 357 ++++++++++++++++++
 .../_Core/src/nodeTester/ConditionalLexer.cpp | 323 ++++++++++++++++
 .../src/nodeTester/ConditionalParser.cpp      | 206 ++++++++++
 .../tests/Test_ConditionalInterpreter.cpp     |  30 ++
 aidge/_Core/tests/Test_ConditionalLexer.cpp   | 142 +++++++
 aidge/_Core/tests/Test_ConditionalParser.cpp  |  74 ++++
 10 files changed, 1829 insertions(+)
 create mode 100644 aidge/_Core/include/nodeTester/ConditionalData.hpp
 create mode 100644 aidge/_Core/include/nodeTester/ConditionalInterpreter.hpp
 create mode 100644 aidge/_Core/include/nodeTester/ConditionalLexer.hpp
 create mode 100644 aidge/_Core/include/nodeTester/ConditionalParser.hpp
 create mode 100644 aidge/_Core/src/nodeTester/ConditionalInterpreter.cpp
 create mode 100644 aidge/_Core/src/nodeTester/ConditionalLexer.cpp
 create mode 100644 aidge/_Core/src/nodeTester/ConditionalParser.cpp
 create mode 100644 aidge/_Core/tests/Test_ConditionalInterpreter.cpp
 create mode 100644 aidge/_Core/tests/Test_ConditionalLexer.cpp
 create mode 100644 aidge/_Core/tests/Test_ConditionalParser.cpp

diff --git a/aidge/_Core/include/nodeTester/ConditionalData.hpp b/aidge/_Core/include/nodeTester/ConditionalData.hpp
new file mode 100644
index 00000000..7477cae9
--- /dev/null
+++ b/aidge/_Core/include/nodeTester/ConditionalData.hpp
@@ -0,0 +1,137 @@
+
+#ifndef _AIDGE_CONDITIONAL_DATA_H_
+#define _AIDGE_CONDITIONAL_DATA_H_
+
+#include <vector>
+#include <string> 
+#include <stdexcept> //error
+#include <memory>
+#include <map>
+namespace Aidge{
+
+
+// struct ConditionalTokenTypes2 {
+
+//     enum class logicalOperators {
+//         AND = 1,
+//         OR,
+//         NOT
+//     };
+
+//   enum class logicalComparators {
+//         EQ,
+//         NEQ
+//     };
+
+//     enum class value {
+//         KEY,
+//         INTEGER,
+//         FLOAT,
+//         STRING,
+//         NODE,
+//         LAMBDA,
+//     };
+
+//     enum class tag {
+//         ARGSEP,
+//         LPAREN,
+//         RPAREN,
+//         STOP
+//     };
+
+//     const std::map<logicalComparators, int> precLogicalOperators{
+//         {logicalOperators::NOT,3},
+//         {logicalOperators::AND,2},
+//         {logicalOperators::OR,1}
+//     };
+// };
+
+
+
+
+
+/////////////////////////
+// the data type in AST Intepretation 
+////////////////////////
+
+class BaseConditionalValue {
+public:
+    virtual ~BaseConditionalValue() {}
+};
+
+template <typename T>
+class ConditionalValue : public BaseConditionalValue {
+public:
+    ConditionalValue(const T& data) : value(data) {}
+    T value;
+};
+
+
+struct ConditionalData {
+    /**
+     * @brief generic type to propagete all the different values in the AST interpretation 
+    */
+    //void* value;
+    std::unique_ptr<BaseConditionalValue> value;
+    const std::type_info* type;
+
+    /////////////////////////////////
+    //
+    ////////////////////////////////
+    /**
+     * @brief set a value 
+    */
+    template <typename T>
+    void setValue(const T& newValue) {
+        // if (std::is_pointer<T>::value) {
+        //     throw std::runtime_error("Pointer type not allowed.");
+        // }
+        deleteValue(); //the old one 
+        //value = new Value<T>(newValue);
+        value = std::make_unique<ConditionalValue<T>>(newValue);
+        type = &typeid(T);
+    }
+
+    /**
+     * @brief set a value for vetor 
+    */
+    template <typename T>
+    T getValue() const {
+        if (type && *type == typeid(T)) {
+            //const Value<T>* typedValue = dynamic_cast<const Value<T>*>(static_cast<const BaseValue*>(value));
+            const ConditionalValue<T>* typedValue = dynamic_cast<const ConditionalValue<T>*>(value.get());
+            if (typedValue) {
+                return typedValue->value;
+            }
+        }
+        throw std::runtime_error(std::string("DATA ERROR ") + type->name() + " != " + typeid(T).name());
+    }
+    ///////////////////////////////////
+    //
+    ///////////////////////////////////
+    std::string getType() const {
+        return  type ? type->name() : "nullptr";
+    }
+    
+
+    template <typename T>
+    bool isTypeEqualTo() const {
+        return (type && *type == typeid(T));
+    }
+
+    void deleteValue() {
+        if (type) {
+            value.reset();
+            type = nullptr;
+        }
+    }
+
+    ~ConditionalData() { // TODO best can we have a liste of type supported ?
+       deleteValue();
+    }
+};
+
+}
+
+
+#endif //_AIDGE_CONDITIONAL_DATA_H_
\ No newline at end of file
diff --git a/aidge/_Core/include/nodeTester/ConditionalInterpreter.hpp b/aidge/_Core/include/nodeTester/ConditionalInterpreter.hpp
new file mode 100644
index 00000000..eb685f88
--- /dev/null
+++ b/aidge/_Core/include/nodeTester/ConditionalInterpreter.hpp
@@ -0,0 +1,291 @@
+
+
+#ifndef _AIDGE_CONDITIONAL_INTERPRETER_H_
+#define _AIDGE_CONDITIONAL_INTERPRETER_H_
+
+#include "nodeTester/ConditionalParser.hpp"
+#include "nodeTester/ConditionalData.hpp"
+
+#include <memory> // for shared_ptr
+#include <unordered_map>
+#include <functional>
+#include "graph/Node.hpp"
+#include <sstream>
+
+
+namespace Aidge{
+
+
+
+//////////////////////////////
+//
+/////////////////////////////
+
+class ConditionalRegisterFunction {
+    //////////////////////////
+    //Safe recaste
+    //////////////////////////
+    
+    
+    template <typename T>
+    T safeCastInput(ConditionalData* data) {
+        //cnvertion and type cheking
+        if (data->isTypeEqualTo<T>()){
+            return data->getValue<T>();
+        }else{
+            throw std::invalid_argument( "incompatible input type " + data->getType() +" "+ typeid(T).name() );
+        }
+       
+    }
+    
+    
+    //convert the output of f to a ConditionalData*
+    template <typename T>
+    ConditionalData* safeCastOutput(T data) {
+        
+        ConditionalData* out = new ConditionalData;
+        out->setValue<T>(data);
+        
+        return out;
+    }
+    
+    
+    
+    
+    //////////////////////
+    // get all the type of the function 
+    //////////////////////
+
+    /**
+     * @brief Retrieves information about a function's return type and argument types.
+     * @tparam T The function type.
+     */
+    template <typename T>
+    struct function_traits;
+    
+
+    /**
+     * @brief Specialization of function_traits for function pointers.
+     * @tparam R The return type of the function.
+     * @tparam Args The argument types of the function.
+     */
+    template <typename R, typename... Args>
+    struct function_traits<R (*)(Args...)> {
+        using return_type = R;
+        static constexpr std::size_t arity = sizeof...(Args);
+    
+        template <std::size_t N>
+        struct argument {
+            static_assert(N < arity, "Index out of range.");
+            using type = typename std::tuple_element<N, std::tuple<Args...>>::type;
+        };
+    };
+
+    /**
+     * @brief Specialization of function_traits for std::function types.
+     * @tparam R The return type of the function.
+     * @tparam Args The argument types of the function.
+     */
+    template <typename R, typename... Args>
+    struct function_traits<std::function<R(Args...)>> {
+        using return_type = R;
+        static constexpr std::size_t arity = sizeof...(Args);
+    
+        template <std::size_t N>
+        struct argument {
+            static_assert(N < arity, "Index out of range.");
+            using type = typename std::tuple_element<N, std::tuple<Args...>>::type;
+        };
+    };
+    
+    /////////////////////
+    //change the function to ConditionalData*(std::vector<ConditionalData*>)
+    /////////////////////
+    
+    /**
+     * @brief Converts a function to a ConditionalData*(std::vector<ConditionalData*>).
+     * @tparam F The type of the function to convert.
+     * @tparam ParamsIdx The indices of the function parameters.
+     * @param f The function to convert.
+     * @return The pointer to the converted function.
+     */
+    template <class F, std::size_t... ParamsIdx>
+    auto funcPointer(F f, std::index_sequence<ParamsIdx...>) {
+        //wrapp the lambda in a new one that as ConditionalData as inputs and output
+    	return [this,f](std::vector<ConditionalData*>  &args) {
+            if (args.size() != sizeof...(ParamsIdx)){
+                std::ostringstream errorMessage;
+                errorMessage << "bad Number of argument: get " << args.size() << " need " << sizeof...(ParamsIdx) << "\n";
+                throw std::runtime_error(errorMessage.str()); 
+            }
+    		//assert(args.size() == sizeof...(ParamsIdx));//the size of the vector valide 
+
+    		using FuncTraits = function_traits<decltype(f)>;
+    		using outType = typename FuncTraits::return_type;
+    		
+    		outType result = f(safeCastInput<typename FuncTraits::template argument<ParamsIdx>::type>(args[ParamsIdx])...);
+    		//typename 
+    		return safeCastOutput<outType>(result);
+    	};
+    }
+    
+        /**
+     * @brief Converts a function pointer to a ConditionalData*(std::vector<ConditionalData*>).
+     * @tparam R The return type of the function.
+     * @tparam Params The parameter types of the function.
+     * @param f The function pointer to convert.
+     * @return The pointer to the converted function.
+     */
+    template <class R,class... Params>
+    auto funcPointer(R (*f)(Params...)) {
+    	return funcPointer(f, std::index_sequence_for<Params...>{});
+    }
+
+    template <class R,class... Params>
+    auto funcPointer(std::function<R(Params...)> f) {
+    	return funcPointer(f, std::index_sequence_for<Params...>{});
+    }
+    
+    
+    ///////////////////
+    // interface
+    ///////////////////
+        
+    public:
+    
+     /**
+     * @brief Default constructor 
+     */
+    ConditionalRegisterFunction(){}
+    
+    
+     /**
+     * @brief Inserts a function into the map with the provided key.
+     * @tparam T The function type.
+     * @param key The key to associate with the function.
+     * @param f The function to insert.
+     */
+    template <class T>
+    void insert(const std::string key,T f){
+        mWlambda.insert({ key, funcPointer(f)});
+    }
+    
+    
+     /**
+     * @brief Runs the function associated with the given key, using the provided vector of input data.
+     * @param key The key of the function to run.
+     * @param datas The vector of input data.
+     * @return A pointer to the output ConditionalData object.
+     */
+    ConditionalData* run(const std::string key,std::vector<ConditionalData*> & datas);
+    
+    private:
+    /// @brief map of name and the converted function.
+    std::map<const std::string, std::function<ConditionalData*(std::vector<ConditionalData*>  &)>> mWlambda;
+};
+
+///////////////////
+//AST tree node
+// ////////////////
+class ConditionalInterpreter
+{
+    private:
+
+  
+    std::shared_ptr<Aidge::AstConditionalNode> mTree;
+    ConditionalRegisterFunction mLambdaRegiter;
+    
+    public:
+    /**
+     * @brief Constructor 
+     * @param ConditionalExpressions The expression of the test to be performed on the nodes
+     * 
+     */
+
+    ConditionalInterpreter(const std::string ConditionalExpressions);
+    
+    /**
+     * @brief Test a node depending of the ConditionalExpressions
+     * @return bool
+     */
+    bool test( const NodePtr nodeOp);
+
+    /**
+     * @brief Interface for inserting custom lambda bool(NodePtr) functions in AST interpretation
+     * @param key The key that will be used to call the function in the expression 
+     * @param f The pointer to function 
+     */
+    void insertLambda(const std::string key,std::function<bool(Aidge::NodePtr)> f);
+
+
+    /////
+
+
+    private:
+    /**
+     * @brief Recursive AST traversal function, using the for interpreting AST nodes function,
+     * using \ref ASTnodeInterpreterF fuctions
+     * @param NodeOp The node currently being tested 
+     * @param nodes The AST given by the parsing process 
+     */
+    std::vector<ConditionalData*> visit(const ASTNodeCh& nodes, const NodePtr NodeOp );
+
+    /**
+     * @defgroup ASTnodeInterpreterF Functions for interpreting AST nodes 
+     * @brief For each node type in the AST, function defines the processing to be performed 
+     *          they return a  std::vector<ConditionalData*> which corresponds to the value(s) obtained 
+     */
+
+    /**
+     * @ingroup ASTnodeInterpreterF
+     * @brief Function that does something.
+     */
+    std::vector<ConditionalData*> fLambda(const std::shared_ptr<AstConditionalNode>& node,std::vector<ConditionalData*> datas);
+    /**
+     * @ingroup ASTnodeInterpreterF
+     * @brief Converted the lexeme to a int and to ConditionalData*
+     */
+    std::vector<ConditionalData*> fStrToInteger(const std::shared_ptr<AstConditionalNode>& node);
+    /**
+     * @ingroup ASTnodeInterpreterF
+     * @brief Converted the lexeme to a float and to ConditionalData*
+     */
+    std::vector<ConditionalData*> fStrToFloat(const std::shared_ptr<AstConditionalNode>& node);
+    /**
+     * @ingroup ASTnodeInterpreterF
+     * @brief Converted the lexeme to a str and to ConditionalData*
+     */
+    std::vector<ConditionalData*> fStrToStr(const std::shared_ptr<AstConditionalNode>& node);
+
+    /**
+     * @ingroup ASTnodeInterpreterF
+     * @brief makes the == operation between two previously converted ConditionalData* 
+     */
+    std::vector<ConditionalData*> fEq(std::vector<ConditionalData*> datas);
+       /**
+     * @ingroup ASTnodeInterpreterF
+     * @brief makes the != operation between two previously converted ConditionalData* 
+     */
+    std::vector<ConditionalData*> fNeq(std::vector<ConditionalData*> datas);
+    /**
+     * @ingroup ASTnodeInterpreterF
+     * @brief makes the && operation between two previously converted ConditionalData* in bool 
+     */
+    std::vector<ConditionalData*> fAnd(std::vector<ConditionalData*> datas);
+        /**
+     * @ingroup ASTnodeInterpreterF
+     * @brief makes the || operation between two previously converted ConditionalData* in bool 
+     */
+    std::vector<ConditionalData*> fOr(std::vector<ConditionalData*> datas);
+
+    /**
+     * @ingroup ASTnodeInterpreterF
+     * @brief makes the ! operation 
+     */
+    std::vector<ConditionalData*> fNot(std::vector<ConditionalData*> datas);
+};
+
+
+}
+
+#endif //_AIDGE_CONDITIONAL_INTERPRETER_H_
diff --git a/aidge/_Core/include/nodeTester/ConditionalLexer.hpp b/aidge/_Core/include/nodeTester/ConditionalLexer.hpp
new file mode 100644
index 00000000..5e0cb0f7
--- /dev/null
+++ b/aidge/_Core/include/nodeTester/ConditionalLexer.hpp
@@ -0,0 +1,153 @@
+/**
+ * @file
+ * @brief 
+ * @version file 1.0.0
+ * @author vl241552
+ * @copyright
+ *  Copyright (c) 2023 CEA, LIST, Embedded Artificial Intelligence Laboratory. All
+ *  rights reserved.
+ */
+
+
+
+#ifndef _AIDGE_CONDITIONAL_LEXER_H_
+#define _AIDGE_CONDITIONAL_LEXER_H_
+
+#include <string>
+#include <regex>
+#include <memory> // for shared_ptr
+
+
+#include <stdexcept> //error
+#include <sstream>
+
+namespace Aidge{
+
+
+
+/**
+ * 7-5 type
+ * 4-0 id
+*/
+enum class ConditionalTokenTypes
+{
+    NOT                 = (1 << 4)+3,
+    AND                 = (1 << 4)+2,
+    OR                  = (1 << 4)+1,
+
+    EQ                  = (1 << 5)+1,
+    NEQ                 = (1 << 5)+2,
+
+    KEY                 = (1 << 6) +1 ,
+    INTEGER             = (1 << 6) +2 ,
+    FLOAT               = (1 << 6) +3 ,
+    STRING              = (1 << 6) +4 ,
+    BOOL                = (1 << 6) +5 ,
+    NODE                = (1 << 6) +6 , //the node ptr
+    LAMBDA              = (1 << 6) +7 , //the fuction TAG 
+
+    ARGSEP              = (1<<7) +1,//sep fuction ,
+    LPAREN              = (1<<7) +2,
+    RPAREN              = (1<<7) +3,
+    STOP = 0,
+};
+
+class ConditionalToken
+{
+/**
+ * @brief token holder
+*/
+
+public:
+/**
+ * @brief Token container
+ * @param type one of the token type
+ * @param lexeme String representing aditional information of the token
+ */
+ConditionalToken(const ConditionalTokenTypes type , const std::string lexeme );
+/**
+ * @brief get the lexeme
+ * 
+ * @return std::string 
+ */
+const std::string getLexeme(void);
+
+/**
+ * @brief get the token type
+ * 
+ * @return ConditionalTokenTypes 
+ */
+const ConditionalTokenTypes getType(void);
+
+
+std::shared_ptr<Aidge::ConditionalToken> copy();
+
+
+std::ostringstream rep(void);
+private:
+
+const std::string mLexeme;
+const ConditionalTokenTypes mType;
+
+};
+
+
+
+class ConditionalLexer
+{
+
+public:
+ConditionalLexer( const std::string ConditionalExpressions );
+
+/**
+ * @brief Get the next token on the ConditionalExpressions
+ * 
+ * @return ConditionalToken 
+ */
+std::shared_ptr<ConditionalToken> getNextToken(void);
+/**
+ * @brief Restart at the start of the ConditionalExpressions 
+ * 
+ */
+void rstPosition(void);
+
+/**
+ * @brief Test if the string is completely read 
+ * @return bool 
+ */
+bool isEnd(void);
+
+
+/**
+ * @brief Get the representation of the class
+ * @return string 
+ */
+const std::string rep(){
+   return mConditionalExpressions;
+}
+
+private:
+
+/**
+ * @brief Constructs an error message to display the character not understood by the lexer 
+ * @return error mesage 
+ */
+std::runtime_error badTokenError(const std::string& currentChars,std::size_t position);
+
+/**
+ * @brief The expression of the test to be performed on the nodes
+ */
+const std::string mConditionalExpressions;
+/**
+ * @brief The lexer's current position in mConditionalExpressions
+ */
+std::size_t mPosition;
+
+};
+
+/////////////////////////////////////
+
+
+}
+
+#endif //_AIDGE_CONDITIONAL_LEXER_H_
\ No newline at end of file
diff --git a/aidge/_Core/include/nodeTester/ConditionalParser.hpp b/aidge/_Core/include/nodeTester/ConditionalParser.hpp
new file mode 100644
index 00000000..c744b1b5
--- /dev/null
+++ b/aidge/_Core/include/nodeTester/ConditionalParser.hpp
@@ -0,0 +1,116 @@
+
+
+
+#ifndef _AIDGE_CONDITIONAL_PARSER_H_
+#define _AIDGE_CONDITIONAL_PARSER_H_
+
+#include "nodeTester/ConditionalLexer.hpp"
+#include <memory> // for shared_ptr
+
+namespace Aidge{
+
+const std::map<ConditionalTokenTypes, std::size_t> ConditionalPrec{
+    {ConditionalTokenTypes::AND,2},
+    {ConditionalTokenTypes::OR,1}
+};
+
+    
+class AstConditionalNode; // Forward declaration
+using ASTNodeCh = std::vector<std::shared_ptr<AstConditionalNode>>;
+
+class AstConditionalNode: public std::enable_shared_from_this<AstConditionalNode>
+{
+    public:
+    AstConditionalNode(std::shared_ptr<ConditionalToken> token,ASTNodeCh child ={});
+    
+    std::string getValue() const;
+    ConditionalTokenTypes getType() const;
+    const ASTNodeCh& getChilds() const ;
+    bool isLeaf() const ;
+    std::size_t nbChild() const;
+    private:
+    const std::shared_ptr<ConditionalToken> mToken;
+    const ASTNodeCh mChild;
+};
+
+
+class ConditionalParser{
+    
+    public:
+    /**
+     * @brief AST graph creation function 
+     * @param ConditionalExpressions String representing the logical fuction to be performed
+     */
+    ConditionalParser(const std::string ConditionalExpressions);
+
+    /**
+     * @brief AST graph creation function 
+     * @return The AST tree 
+     */
+    std::shared_ptr<AstConditionalNode> parse(void);
+
+
+    private:
+    /**
+     * @brief restart at the start of the ConditionalExpressions for LEXER and restart  mCurrentToken
+     * 
+     */
+    void rstParser(void);
+
+
+
+    //////////////////
+
+    /**
+     * @defgroup ParsingFunctions Function for creating AST
+     * @brief Functions for recursive construction of the AST representing grammar rules
+     */
+
+    /**
+     * @ingroup ParsingFunctions
+     * @brief Token reading and verification function  
+     * 
+     */
+    void ackToken(ConditionalTokenTypes  tokenType);
+
+    /**
+     * @ingroup ParsingFunctions
+     * @brief Function of grammar rules for values : (KEY|INTEGER|FOAT|STRING|LAMBDA lambda)
+     * @return AST node 
+     */
+    std::shared_ptr<AstConditionalNode> constructAstVal(void);
+    /**
+    * @ingroup ParsingFunctions
+    * @brief Function of grammar rules for comparison : val (EQ|NEQ) val | LPAREN expr RPAREN
+    * @return AST node 
+    */
+    std::shared_ptr<AstConditionalNode> constructAstCmpr(void);
+    /**
+    * @ingroup ParsingFunctions
+    * @brief Function of grammar rules for arguments of a lambda : LAMBDA val (ARGSEP val)* RPAREN
+    * @return AST node 
+    */
+    std::shared_ptr<AstConditionalNode> constructAstLambda(void);
+    /**
+    * @ingroup ParsingFunctions
+    * @brief Function of grammar rules for a expresion : cmpr ((AND | OR) cmpr)*
+    * @return AST node 
+    */
+    std::shared_ptr<AstConditionalNode> constructAstExpr(std::size_t precLimit = 0);
+
+
+    /**
+    * @brief The actual token in the parce
+    */
+    std::shared_ptr<ConditionalToken> mCurrentToken;
+    /**
+    * @brief The lexem use
+    */
+    ConditionalLexer mLexer;
+
+};
+
+
+}
+
+#endif //_AIDGE_CONDITIONAL_PARSER_H_
diff --git a/aidge/_Core/src/nodeTester/ConditionalInterpreter.cpp b/aidge/_Core/src/nodeTester/ConditionalInterpreter.cpp
new file mode 100644
index 00000000..15c1e456
--- /dev/null
+++ b/aidge/_Core/src/nodeTester/ConditionalInterpreter.cpp
@@ -0,0 +1,357 @@
+#include "nodeTester/ConditionalInterpreter.hpp"
+using namespace Aidge; 
+
+
+///////////////////////////////
+//ConditionalRegisterFunction
+///////////////////////////////
+
+    ConditionalData* ConditionalRegisterFunction::run(const std::string key,std::vector<ConditionalData*> & datas){
+
+        auto lambdaIt = mWlambda.find(key);
+        if (lambdaIt != mWlambda.end()) {
+            return lambdaIt->second(datas);
+        }else {
+            throw std::runtime_error("can not run Lambda due to invalid key: " + key);
+        }
+    }
+
+//////////////////////
+//ConditionalInterpreter
+///////////////////////
+    ConditionalInterpreter::ConditionalInterpreter(const std::string ConditionalExpressions)
+    :mLambdaRegiter()
+    {
+
+        ConditionalParser conditionalParser = ConditionalParser(ConditionalExpressions);
+        mTree = conditionalParser.parse();
+        ///lambda by default
+        mLambdaRegiter.insert("getType",+[](NodePtr NodeOp){return NodeOp->type();});
+
+    }
+    
+
+    bool ConditionalInterpreter::test( const NodePtr nodeOp)
+    {
+        try{
+            std::vector<ConditionalData*> r =  visit({mTree},nodeOp);
+   
+        if (r.size() != 1){
+            throw std::runtime_error("Multy output interpretation output");
+        }else{
+            if (!r[0]->isTypeEqualTo<bool>()){
+                throw std::runtime_error("TEST OUT MUST BE A BOOL ");
+            }else{
+                return r[0]->getValue<bool>();
+            }
+        }
+
+        }catch(const std::exception& e){
+            std::ostringstream errorMessage;
+            errorMessage << "Error in test " << "\n\t" << e.what()  << "\n";
+            throw std::runtime_error(errorMessage.str()); 
+        }
+
+    }
+
+    void ConditionalInterpreter::insertLambda(const std::string key,std::function<bool(Aidge::NodePtr)> f){
+        mLambdaRegiter.insert<std::function<bool(Aidge::NodePtr)> >(key, f);
+    }
+
+    /////
+    std::vector<ConditionalData*> ConditionalInterpreter::visit(const ASTNodeCh& nodes, const NodePtr nodeOp ){
+            std::vector<ConditionalData*> dataVector;
+
+            for ( std::shared_ptr<AstConditionalNode> node : nodes) {
+                try{
+                    switch (node->getType()){
+                        ///////////////////////////////////
+                        //OPERATOR
+                        /////////////////////////////////// 
+                        case ConditionalTokenTypes::NOT:
+                            {
+                            std::vector<ConditionalData*> tmp = fNot(visit(node->getChilds(),nodeOp));
+                            dataVector.insert(dataVector.end(), tmp.begin(), tmp.end());
+                            }
+                            break;
+                        case ConditionalTokenTypes::AND:
+                            {
+                            std::vector<ConditionalData*> tmp = fAnd(visit(node->getChilds(),nodeOp));
+                            dataVector.insert(dataVector.end(), tmp.begin(), tmp.end());
+                            }
+                            break;
+                        case ConditionalTokenTypes::OR:
+                            {
+                            std::vector<ConditionalData*> tmp = fOr(visit(node->getChilds(),nodeOp));
+                            dataVector.insert(dataVector.end(), tmp.begin(), tmp.end());
+                            }
+                            break;
+                        case ConditionalTokenTypes::EQ:
+                            {
+                            std::vector<ConditionalData*> tmp = fEq(visit(node->getChilds(),nodeOp));
+                            dataVector.insert(dataVector.end(), tmp.begin(), tmp.end());
+                            }
+                            break;
+                        case ConditionalTokenTypes::NEQ:
+                            {
+                            std::vector<ConditionalData*> tmp = fNeq(visit(node->getChilds(),nodeOp));
+                            dataVector.insert(dataVector.end(), tmp.begin(), tmp.end());
+                            }
+                            break;
+
+                        ///////////////////////////////////
+                        //VALUE
+                        ///////////////////////////////////    
+                    
+                        case ConditionalTokenTypes::KEY:
+                            
+                            break;
+                        case ConditionalTokenTypes::INTEGER:
+                            {
+                            std::vector<ConditionalData*> tmp = fStrToInteger(node);
+                            dataVector.insert(dataVector.end(), tmp.begin(), tmp.end());
+                            }
+                            break;
+                        case ConditionalTokenTypes::FLOAT:
+                            {
+                            std::vector<ConditionalData*> tmp = fStrToFloat(node);
+                            dataVector.insert(dataVector.end(), tmp.begin(), tmp.end());
+                            }
+                            break;
+                        case ConditionalTokenTypes::STRING:
+                            {
+                            std::vector<ConditionalData*> tmp = fStrToStr(node);
+                            dataVector.insert(dataVector.end(), tmp.begin(), tmp.end());
+                            }
+                            break;
+                    
+                        case ConditionalTokenTypes::NODE: //TODO
+                            {
+
+                            ConditionalData* data = new ConditionalData;
+                            data->setValue<NodePtr>(nodeOp);
+                            std::vector<ConditionalData*> tmp = {data};
+                            dataVector.insert(dataVector.end(), tmp.begin(), tmp.end());
+
+                            }
+                            break;
+
+                        case ConditionalTokenTypes::LAMBDA:
+                            {
+                            std::vector<ConditionalData*> tmp = fLambda(node,visit(node->getChilds(),nodeOp));
+                            dataVector.insert(dataVector.end(), tmp.begin(), tmp.end());
+                            }
+                            break;
+
+                        case ConditionalTokenTypes::BOOL: //TODO
+                            {
+                            ConditionalData* data = new ConditionalData;
+                            
+                            if(node->getValue() == "true"){
+                                data->setValue<bool>(true);
+                            }else{
+                                data->setValue<bool>(false);
+                            }
+                            
+                            std::vector<ConditionalData*> tmp = {data};
+                            dataVector.insert(dataVector.end(), tmp.begin(), tmp.end());
+                            }
+                            break;
+
+                        case ConditionalTokenTypes::ARGSEP:
+                        case ConditionalTokenTypes::LPAREN:
+                        case ConditionalTokenTypes::RPAREN:
+                        case ConditionalTokenTypes::STOP:
+                        default:
+                            throw std::runtime_error("NODE TYPE NOT SUPORTED IN ConditionalInterpreter");
+                    }
+                }catch(const std::exception& e){
+                    std::ostringstream errorMessage;
+                    errorMessage << "Error in visiting AST for node"<< nodeOp->name() << "\n\t" << e.what()  << "\n";
+                    throw std::runtime_error(errorMessage.str()); 
+                }
+            }
+
+            return dataVector;
+    }
+
+
+    //////////////////////
+    //value convertor
+    /////////////////////
+
+
+    std::vector<ConditionalData*> ConditionalInterpreter::fStrToInteger(const std::shared_ptr<AstConditionalNode>& node)
+    {
+        std::vector<ConditionalData*> dataVector;
+        ConditionalData* data = new ConditionalData;
+        data->setValue<int>(std::stoi(node->getValue()));
+        dataVector.push_back(data);
+        return dataVector;
+    }
+
+    std::vector<ConditionalData*> ConditionalInterpreter::fStrToFloat(const std::shared_ptr<AstConditionalNode>& node)
+    {
+        std::vector<ConditionalData*> dataVector;
+        ConditionalData* data = new ConditionalData;
+        data->setValue<float>(std::stof(node->getValue()));
+        dataVector.push_back(data);
+        return dataVector;
+    }
+
+    std::vector<ConditionalData*> ConditionalInterpreter::fStrToStr(const std::shared_ptr<AstConditionalNode>& node)
+    {
+        std::vector<ConditionalData*> dataVector;
+        ConditionalData* data = new ConditionalData;
+        data->setValue<std::string>(node->getValue());
+        dataVector.push_back(data);
+        return dataVector;
+    }
+
+    std::vector<ConditionalData*> ConditionalInterpreter::fLambda(const std::shared_ptr<AstConditionalNode>& node,std::vector<ConditionalData*> datas) 
+    {
+        //if the lambda have input
+        std::vector<ConditionalData*> dataVector;
+        ConditionalData* data;
+        try {
+            data = mLambdaRegiter.run(node->getValue(),datas);
+        } catch (const std::exception& e) {
+            std::ostringstream errorMessage;
+            errorMessage << "Error in conditional interpretation when run the "<<  node->getValue() <<" Lambda\n\t" << e.what()  << "\n";
+            throw std::runtime_error(errorMessage.str()); 
+        }
+        dataVector.push_back(data);
+        datas.clear();
+        return dataVector;
+    }
+
+    std::vector<ConditionalData*> ConditionalInterpreter::fEq(std::vector<ConditionalData*> datas)
+    {
+        if (datas.size() != 2){
+            throw std::runtime_error("EQ need 2 arg and get :" + datas.size());
+        }
+        auto a = datas[0];
+        auto b = datas[1];
+
+        if (a->getType() != b->getType()){
+            throw std::runtime_error("EQ Unsuported between type :" + a->getType() +" "+ b->getType());
+        }
+
+        std::vector<ConditionalData*> dataVector;
+
+        ConditionalData* data = new ConditionalData;
+
+        if (a->isTypeEqualTo<int>()) {
+           data->setValue<bool>( a->getValue<int>() == b->getValue<int>());
+        }else if (a->isTypeEqualTo<float>()){
+           data->setValue<bool>( a->getValue<float>() == b->getValue<float>());
+        }else if (a->isTypeEqualTo<std::string>()){
+           data->setValue<bool>( a->getValue<std::string>() == b->getValue<std::string>());
+        }else if (a->isTypeEqualTo<bool>()){
+           data->setValue<bool>( a->getValue<bool>() == b->getValue<bool>());
+        }else{
+           throw std::runtime_error("EQ Unknown type encountered :" + a->getType() );
+        }
+        dataVector.push_back(data);
+        datas.clear();
+        return dataVector;
+    }
+
+    std::vector<ConditionalData*> ConditionalInterpreter::fNeq(std::vector<ConditionalData*> datas)
+    {
+        if (datas.size() != 2){
+             throw std::runtime_error("NEQ need 2 arg and get :" + datas.size());
+        }
+        auto a = datas[0];
+        auto b = datas[1];
+
+        if (a->getType() != b->getType()){
+            throw std::runtime_error("NEQ Unsuported between type :" + a->getType() +" "+ b->getType());
+        }
+
+        std::vector<ConditionalData*> dataVector;
+
+        ConditionalData* data = new ConditionalData;
+
+        if (a->isTypeEqualTo<int>()) {
+           data->setValue<bool>( a->getValue<int>() != b->getValue<int>());
+        }else if (a->isTypeEqualTo<float>()){
+           data->setValue<bool>( a->getValue<float>() != b->getValue<float>());
+        }else if (a->isTypeEqualTo<std::string>()){
+           data->setValue<bool>( a->getValue<std::string>() != b->getValue<std::string>());
+        }else
+        {
+           throw std::runtime_error("NEQ Unknown type encountered :" + a->getType() );
+        }
+        dataVector.push_back(data);
+        datas.clear();
+        return dataVector;
+    }
+
+    std::vector<ConditionalData*> ConditionalInterpreter::fAnd(std::vector<ConditionalData*> datas)
+    {
+        if (datas.size() != 2){
+           throw std::runtime_error("AND need 2 arg and get :" + datas.size());
+        }
+        auto a = datas[0];
+        auto b = datas[1];
+
+        std::vector<ConditionalData*> dataVector;
+
+        if (a->getType() != typeid(bool).name() || b->getType() != typeid(bool).name()){
+            throw std::runtime_error("AND Unknown type encountered need bool get :" + a->getType() );
+        }
+
+        ConditionalData* data = new ConditionalData;
+        data->setValue<bool>( a->getValue<bool>() && b->getValue<bool>());
+        
+
+        dataVector.push_back(data);
+        datas.clear();
+        return dataVector;
+    }
+
+    std::vector<ConditionalData*> ConditionalInterpreter::fOr(std::vector<ConditionalData*> datas)
+    {
+        if (datas.size() != 2){
+             throw std::runtime_error("OR need 2 arg and get :" + datas.size());
+        }
+        auto a = datas[0];
+        auto b = datas[1];
+
+        std::vector<ConditionalData*> dataVector;
+
+        if (a->getType() != typeid(bool).name() || b->getType() != typeid(bool).name()){
+             throw std::runtime_error("OR Unknown type encountered need bool get :" + a->getType() );
+        }
+
+        ConditionalData* data = new ConditionalData;
+        data->setValue<bool>( a->getValue<bool>() || b->getValue<bool>());
+        
+
+        dataVector.push_back(data);
+        datas.clear();
+        return dataVector;
+    }
+
+    std::vector<ConditionalData*> ConditionalInterpreter::fNot(std::vector<ConditionalData*> datas)
+        {
+            if (datas.size() != 1){
+                throw std::runtime_error("not need 1 arg and get :" + datas.size());
+            }
+            auto a = datas[0];
+
+            std::vector<ConditionalData*> dataVector;
+
+            if (a->getType() != typeid(bool).name()){
+                throw std::runtime_error("NOT Unknown type encountered need bool get :" + a->getType() );
+            }
+
+            ConditionalData* data = new ConditionalData;
+            data->setValue<bool>( !a->getValue<bool>() );
+            
+
+            dataVector.push_back(data);
+            datas.clear();
+            return dataVector;
+        }
diff --git a/aidge/_Core/src/nodeTester/ConditionalLexer.cpp b/aidge/_Core/src/nodeTester/ConditionalLexer.cpp
new file mode 100644
index 00000000..52406947
--- /dev/null
+++ b/aidge/_Core/src/nodeTester/ConditionalLexer.cpp
@@ -0,0 +1,323 @@
+#include "nodeTester/ConditionalLexer.hpp"
+
+using namespace Aidge; 
+
+//////////////////
+//ConditionalToken
+//////////////////
+ConditionalToken::ConditionalToken(const ConditionalTokenTypes type , const std::string lexeme ):
+mLexeme(lexeme),
+mType(type)
+{
+
+}
+
+const std::string ConditionalToken::getLexeme(void){
+    return mLexeme;
+}
+
+const ConditionalTokenTypes ConditionalToken::getType(void){
+    return mType;
+}
+
+std::shared_ptr<Aidge::ConditionalToken> ConditionalToken::copy(){
+    auto newToken = std::make_shared<ConditionalToken>(mType,mLexeme);
+    return newToken;
+}
+
+std::ostringstream ConditionalToken::rep(void){
+    std::ostringstream out;
+
+    switch (mType){
+        case ConditionalTokenTypes::AND:
+            out << "AND" ;
+            break;
+        case ConditionalTokenTypes::OR:
+            out << "OR" ;
+            break;
+        case ConditionalTokenTypes::EQ:
+            out << "EQ" ;
+            break;
+        case ConditionalTokenTypes::NEQ:
+            out << "NEQ" ;
+            break;
+    
+        case ConditionalTokenTypes::KEY:
+            out << "KEY" ;
+            break;
+        case ConditionalTokenTypes::INTEGER:
+            out << "INTEGER" ;
+            break;
+        case ConditionalTokenTypes::FLOAT:
+            out << "FLOAT" ;
+            break;
+        case ConditionalTokenTypes::STRING:
+            out << "STRING" ;
+            break;
+    
+        case ConditionalTokenTypes::LAMBDA:
+            out << "LAMBDA" ;
+            break;
+        case ConditionalTokenTypes::ARGSEP:
+            out << "ARGSEP" ;
+            break;
+        case ConditionalTokenTypes::NODE:
+            out << "NODE" ;
+            break;
+    
+        case ConditionalTokenTypes::LPAREN:
+            out << "LPAREN" ;
+            break;
+        case ConditionalTokenTypes::RPAREN:
+            out << "RPAREN" ;
+            break;
+        case ConditionalTokenTypes::STOP:
+            out << "STOP" ;
+            break;
+        default:
+            out << "???" ;
+    }
+    out << " ("  << mLexeme <<")" << "\n";
+    
+    return out;
+}
+//////////////////
+//ConditionalLexer
+//////////////////
+
+
+ConditionalLexer::ConditionalLexer( const std::string ConditionalExpressions):
+mConditionalExpressions(ConditionalExpressions)
+{
+    mPosition = 0;
+}
+
+std::shared_ptr<ConditionalToken> ConditionalLexer::getNextToken(void){
+    std::string currentChars = "";
+
+    while (mPosition < mConditionalExpressions.length())
+    {
+        //erase all space 
+        if (mConditionalExpressions[mPosition] != ' ')
+        {
+            currentChars += mConditionalExpressions[mPosition];
+        }
+        else
+        {
+            mPosition++;
+            continue;
+        }
+        //performe tokenisation, find a regex and make a new token
+        
+        if (std::regex_match(currentChars,std::regex("\\&\\&")))// the AND TOKEN 
+        {
+            mPosition++;
+            return std::make_shared<ConditionalToken>(ConditionalTokenTypes::AND,"");
+        }
+        else if (std::regex_match(currentChars,std::regex("\\|\\|")))// the OR TOKEN 
+        {
+            mPosition++;
+            return std::make_shared<ConditionalToken>(ConditionalTokenTypes::OR,"");
+        }
+        else if (std::regex_match(currentChars,std::regex("\\!")))// the Not and not equ
+        {
+            mPosition++;
+            if ( mPosition < mConditionalExpressions.length()){
+                currentChars += mConditionalExpressions[mPosition];
+                if(std::regex_match(currentChars,std::regex("!="))){
+                    mPosition++;
+                    return std::make_shared<ConditionalToken>(ConditionalTokenTypes::NEQ,"");
+                }else{
+                     return std::make_shared<ConditionalToken>(ConditionalTokenTypes::NOT,"");
+                }
+            }
+            //a not at the end not ok but it's the parseur work
+            return std::make_shared<ConditionalToken>(ConditionalTokenTypes::NOT,"");
+        }
+        else if (std::regex_match(currentChars,std::regex("==")))// the EQ TOKEN 
+        {
+            mPosition++;
+            return std::make_shared<ConditionalToken>(ConditionalTokenTypes::EQ,"");
+        }
+        // else if (std::regex_match(currentChars,std::regex("!=")))// the NEQ TOKEN 
+        // {
+        //     mPosition++;
+        //     return std::make_shared<ConditionalToken>(ConditionalTokenTypes::NEQ,"");
+        // }
+        else if (std::regex_match(currentChars,std::regex("\\(")))// the LPAREN TOKEN 
+        {
+            mPosition++;
+            return std::make_shared<ConditionalToken>(ConditionalTokenTypes::LPAREN,"");
+        }
+        else if (std::regex_match(currentChars,std::regex("\\)")))// the RPAREN TOKEN 
+        {
+            mPosition++;
+            return std::make_shared<ConditionalToken>(ConditionalTokenTypes::RPAREN,"");
+        }
+        else if (std::regex_match(currentChars,std::regex(",")))// the RPAREN TOKEN 
+        {
+            mPosition++;
+            return std::make_shared<ConditionalToken>(ConditionalTokenTypes::ARGSEP,"");
+        }
+        else if (std::regex_match(currentChars,std::regex("\\$")))// the ACTNode TOKEN 
+        {
+            mPosition++;
+            return std::make_shared<ConditionalToken>(ConditionalTokenTypes::NODE,"");
+        }
+
+
+        /////
+        //non const lent token
+        /////
+
+        //LAMBDA, KEY , bool //the fuction TAG 
+        else if (std::regex_match(currentChars,std::regex("[A-Za-z_]")))// the KEY TOKEN (a char next )
+        {   
+            //read all the key 
+            bool isLambda = false;
+            std::regex keyRegex("[A-Za-z_0-9]+");
+            std::regex LambdaRegex("[A-Za-z_0-9]+\\(");
+
+            while ( mPosition < mConditionalExpressions.length()) {
+                if(!std::regex_match(currentChars,keyRegex) && !std::regex_match(currentChars,LambdaRegex))
+                {
+                    currentChars.pop_back(); //the last char is the problemes
+                    break;
+                }
+                else if (std::regex_match(currentChars,LambdaRegex)){
+                    isLambda = true;
+                }
+                mPosition++;
+                currentChars += mConditionalExpressions[mPosition];
+            }
+            //we end the match 2 posibility 
+            //we are at the end of the mConditionalExpressions and we need to ensure the match
+            //we are not we can continu
+            if (mPosition == mConditionalExpressions.length()-1)
+            {
+                if (!std::regex_match(currentChars,keyRegex) && !std::regex_match(currentChars,LambdaRegex))
+                {
+                    throw badTokenError(currentChars,mPosition);
+                }
+                //mPosition++; // we stop all by going pos > lengt
+            }
+
+
+            if (std::regex_match(currentChars,std::regex("(true|false)"))){
+                return std::make_shared<ConditionalToken>(ConditionalTokenTypes::BOOL,currentChars);
+
+            } else if (isLambda){
+                currentChars.pop_back();//pop the ( of the lambda
+                return std::make_shared<ConditionalToken>(ConditionalTokenTypes::LAMBDA,currentChars);
+            } else{
+                return std::make_shared<ConditionalToken>(ConditionalTokenTypes::KEY,currentChars);
+            }
+            
+        }
+        //numeric value 
+        else if (std::regex_match(currentChars,std::regex("[0-9]")))// the KEY TOKEN (a char next )
+        {   
+            //read all the key 
+            bool isFloat = false;
+            std::regex integerRegex("[0-9]+$");
+            std::regex floatRegex("[0-9]+\\.[0-9]*$");
+
+            while ( mPosition < mConditionalExpressions.length()) {
+
+                if(!std::regex_match(currentChars,integerRegex) && !std::regex_match(currentChars,floatRegex))
+                {
+                    currentChars.pop_back(); // the last char match is not a good one 
+                    break;
+                }
+                else if (std::regex_match(currentChars,floatRegex)){
+                    isFloat = true;
+                }
+                mPosition++;
+                currentChars += mConditionalExpressions[mPosition];
+            }
+            //we end the match 2 posibility 
+            //we are at the end of the mConditionalExpressions and we need to ensure the match
+            //we are not we can continu
+            if (mPosition == mConditionalExpressions.length()-1)
+            {
+                if (!std::regex_match(currentChars,integerRegex) && !std::regex_match(currentChars,floatRegex))
+                {
+                     throw badTokenError(currentChars,mPosition);
+                }
+            }
+            
+            if(isFloat){
+                return std::make_shared<ConditionalToken>(ConditionalTokenTypes::FLOAT,currentChars);
+            }else{
+                return std::make_shared<ConditionalToken>(ConditionalTokenTypes::INTEGER,currentChars);
+            }
+            
+        }
+        //string TODO
+        else if (std::regex_match(currentChars,std::regex("\'"))) // TODO ' or \'
+        {
+            std::regex strRegex("\'[A-Za-z_0-9\\s]*\'$");
+            while ( mPosition < mConditionalExpressions.length()) {
+                if(std::regex_match(currentChars,strRegex)){
+                    break;
+                }
+                mPosition++;
+                currentChars += mConditionalExpressions[mPosition];
+            }
+
+            //test the end condition
+            if (mPosition == mConditionalExpressions.length()-1 ){
+                if (!std::regex_match(currentChars,strRegex)){
+                     throw badTokenError(currentChars,mPosition);
+                }
+                //mPosition++; // we stop all by going pos > lengt
+            }
+
+            mPosition++; // go after the last " 
+            //erase the " char
+            currentChars.pop_back();
+            currentChars.erase(0,1);
+
+            return std::make_shared<ConditionalToken>(ConditionalTokenTypes::STRING,currentChars);
+
+        }
+
+        //Array TODO
+
+        mPosition++;
+    }
+
+    //no more to find no one match the currentChars 
+    if (currentChars.empty()) {
+        return  std::make_shared<ConditionalToken>(ConditionalTokenTypes::STOP,"");  // Null shared pointer ;
+    }else{
+        //std::ostringstream errorMessage;
+        //errorMessage << "\nBad syntax " << currentChars << " :\n" << mConditionalExpressions;
+        throw badTokenError(currentChars,mPosition);
+    }
+    
+}
+
+void ConditionalLexer::rstPosition(void){
+    if (isEnd()){
+        mPosition = 0;
+    }else{
+        throw badTokenError("end rst",mPosition);
+    }
+    
+}
+
+bool ConditionalLexer::isEnd(void){
+    return mPosition >= mConditionalExpressions.length();
+}
+
+std::runtime_error ConditionalLexer::badTokenError(const std::string& currentChars,std::size_t position){
+    std::ostringstream errorMessage;
+    errorMessage << "\nBad syntax " << currentChars << " :\n" << mConditionalExpressions << "\n";
+     for (std::size_t i = 0; i < position; i++) {
+        errorMessage << ' ';
+    }
+    errorMessage << "^\n";
+
+    return std::runtime_error(errorMessage.str());
+}
\ No newline at end of file
diff --git a/aidge/_Core/src/nodeTester/ConditionalParser.cpp b/aidge/_Core/src/nodeTester/ConditionalParser.cpp
new file mode 100644
index 00000000..ca5dab51
--- /dev/null
+++ b/aidge/_Core/src/nodeTester/ConditionalParser.cpp
@@ -0,0 +1,206 @@
+
+#include "nodeTester/ConditionalParser.hpp"
+
+using namespace Aidge;
+
+
+AstConditionalNode::AstConditionalNode(std::shared_ptr<ConditionalToken> token,ASTNodeCh child )
+:mToken(token),mChild(child){}
+
+std::string AstConditionalNode::getValue() const{
+    return mToken->getLexeme();
+}
+
+ConditionalTokenTypes AstConditionalNode::getType() const{
+    return mToken->getType();
+}
+
+bool AstConditionalNode::isLeaf() const {
+    return mChild.size() == 0;
+}
+
+const ASTNodeCh& AstConditionalNode::getChilds() const {
+        return mChild;
+}
+
+std::size_t AstConditionalNode::nbChild() const{
+    return mChild.size();
+}
+
+//////////////////////////////
+//ConditionalParser
+//////////////////////////////
+
+ConditionalParser::ConditionalParser(const std::string ConditionalExpressions):mLexer(ConditionalExpressions){
+    mCurrentToken = mLexer.getNextToken();
+}
+
+void ConditionalParser::rstParser(void){
+    mLexer.rstPosition();
+    mCurrentToken = mLexer.getNextToken();
+}
+
+void ConditionalParser::ackToken(ConditionalTokenTypes  tokenType){
+    if(mCurrentToken->getType() == tokenType ){
+
+        try {
+            mCurrentToken = mLexer.getNextToken();
+        } catch (const std::runtime_error& e) {
+            std::ostringstream errorMessage;
+            errorMessage << "Conditional Lexer error in Parser :\n"<< e.what() << std::endl;
+            throw std::runtime_error(errorMessage.str());
+        }
+    }else{
+
+        std::ostringstream errorMessage;
+        errorMessage << "Bad syntax ConditionalParser " << static_cast<int>(mCurrentToken->getType())  <<"!="<< static_cast<int>(tokenType) << "\n";
+        errorMessage << mLexer.rep();
+        throw std::runtime_error(errorMessage.str());
+    }
+}
+
+std::shared_ptr<AstConditionalNode> ConditionalParser::constructAstVal(void){
+    /*
+    val : (KEY|INTEGER|FOAT|STRING|LAMBDA)
+    */
+    std::shared_ptr<Aidge::ConditionalToken> token = mCurrentToken->copy();
+
+    if (token->getType() == ConditionalTokenTypes::KEY){
+        ackToken(ConditionalTokenTypes::KEY);
+        return std::make_shared<AstConditionalNode>(token);
+    }
+    else if(token->getType() == ConditionalTokenTypes::INTEGER){
+        ackToken(ConditionalTokenTypes::INTEGER);
+        return std::make_shared<AstConditionalNode>(token);
+    }
+    else if(token->getType() == ConditionalTokenTypes::FLOAT){
+        ackToken(ConditionalTokenTypes::FLOAT);
+        return std::make_shared<AstConditionalNode>(token);
+    }
+    else if(token->getType() == ConditionalTokenTypes::BOOL){
+        ackToken(ConditionalTokenTypes::BOOL);
+        return std::make_shared<AstConditionalNode>(token);
+    }
+    else if(token->getType() == ConditionalTokenTypes::STRING){
+        ackToken(ConditionalTokenTypes::STRING);
+        return std::make_shared<AstConditionalNode>(token);
+
+    }else if(token->getType() == ConditionalTokenTypes::NODE){
+        ackToken(ConditionalTokenTypes::NODE);
+        return std::make_shared<AstConditionalNode>(token);
+
+    }else if(token->getType() == ConditionalTokenTypes::LAMBDA){
+        return constructAstLambda();
+    }
+
+   throw std::runtime_error("ConditionalParser unknow val type "+ token->rep().str() + "\n" + mLexer.rep());
+
+}
+
+std::shared_ptr<AstConditionalNode> ConditionalParser::constructAstLambda(void){
+    /*
+    AstLambda :  LAMBDA val (ARGSEP val)* RPAREN
+    */
+    std::shared_ptr<Aidge::ConditionalToken> tokenLdb = mCurrentToken->copy();
+    ackToken(ConditionalTokenTypes::LAMBDA);
+    ASTNodeCh paramLambda;
+    //AT LEAST ONE VALUE AS INPUT OF A LAMBDA
+    paramLambda.push_back(constructAstVal());
+    while (mCurrentToken->getType() != ConditionalTokenTypes::RPAREN)
+    {
+        ackToken(ConditionalTokenTypes::ARGSEP);
+        paramLambda.push_back(constructAstVal());
+    }
+    ackToken(ConditionalTokenTypes::RPAREN);
+    return std::make_shared<AstConditionalNode>(tokenLdb,paramLambda);
+}
+
+std::shared_ptr<AstConditionalNode> ConditionalParser::constructAstCmpr(void){
+      /*
+        cmpr   : val (EQ|NEQ) val | LPAREN expr RPAREN
+        NOT ir ?
+      */
+     std::shared_ptr<Aidge::ConditionalToken> token = mCurrentToken->copy();
+     //we can check the type relation ir  key (EQ|NEQ) val | val (EQ|NEQ) key , but val (EQ|NEQ) val is valid ?
+     if (token->getType() == ConditionalTokenTypes::LPAREN)
+     {
+        ackToken(ConditionalTokenTypes::LPAREN);
+        std::shared_ptr<AstConditionalNode> node = constructAstExpr();
+        ackToken(ConditionalTokenTypes::RPAREN);
+        return node;
+     }else{
+
+        std::shared_ptr<AstConditionalNode> node = constructAstVal();
+        token = mCurrentToken->copy();
+        if (token->getType() == ConditionalTokenTypes::EQ){
+            ackToken(ConditionalTokenTypes::EQ);
+            return std::make_shared<AstConditionalNode>(token,ASTNodeCh{node,constructAstVal()});
+        }else if(token->getType() == ConditionalTokenTypes::NEQ){
+            ackToken(ConditionalTokenTypes::NEQ);
+            return std::make_shared<AstConditionalNode>(token,ASTNodeCh{node,constructAstVal()});
+        }
+
+     }
+}
+
+std::shared_ptr<AstConditionalNode> ConditionalParser::constructAstExpr(std::size_t precLimit /*= 0*/){
+    /*
+        expr   : cmpr ((AND | OR) cmpr)*
+        the NOT is not binary OP can be use in pratt
+        precedence H to L: TODO
+        AND
+        OR
+    */
+
+   //the not 
+    std::shared_ptr<AstConditionalNode> left;
+    std::shared_ptr<Aidge::ConditionalToken> token = mCurrentToken->copy();
+    
+    if (mCurrentToken->getType() == ConditionalTokenTypes::NOT  ){
+        ackToken(ConditionalTokenTypes::NOT );
+        left= std::make_shared<AstConditionalNode>(token,ASTNodeCh{constructAstCmpr()});
+    }else{
+        left= constructAstCmpr();
+    }
+    
+    //pratt
+    while (mCurrentToken->getType() != ConditionalTokenTypes::STOP ) //security 
+    {
+        std::shared_ptr<Aidge::ConditionalToken> token = mCurrentToken->copy();
+        //if the token is not in the map is not a operator so we consider a prec of 0 
+        if (ConditionalPrec.find(token->getType()) ==ConditionalPrec.end() ){
+            return left;
+        }
+
+        //if my actual operator have a prec <= of the last operator 
+        std::size_t prec = ConditionalPrec.at(token->getType());
+        if (prec <= precLimit){
+            return left;
+        }
+
+        //Act all AND and OR
+        ackToken(token->getType());
+
+        std::shared_ptr<AstConditionalNode> right = constructAstExpr(prec);
+
+        //i'm not sur what append to newNode 
+        //std::shared_ptr<AstConditionalNode> newNode = std::make_shared<AstConditionalNode>(token,ASTNodeCh{left,constructAstCmpr()});
+        std::shared_ptr<AstConditionalNode> newNode = std::make_shared<AstConditionalNode>(token,ASTNodeCh{left,right});
+        left = newNode;
+    }
+    return left;
+}
+
+
+std::shared_ptr<AstConditionalNode> ConditionalParser::parse(void){
+    /*
+        expr   : cmpr ((AND | OR) cmpr)*
+        cmpr   : val (EQ|NEQ) val | LPAREN expr RPAREN | BOOL | LAMBDA 
+        val    : (KEY|INTEGER|FOAT|STRING|LAMBDA)
+        lambda :  LAMBDA val (ARGSEP val)* RPAREN
+    */
+    std::shared_ptr<AstConditionalNode> astTree = constructAstExpr();
+
+    rstParser();
+    return astTree;
+}
\ No newline at end of file
diff --git a/aidge/_Core/tests/Test_ConditionalInterpreter.cpp b/aidge/_Core/tests/Test_ConditionalInterpreter.cpp
new file mode 100644
index 00000000..ecf8adc0
--- /dev/null
+++ b/aidge/_Core/tests/Test_ConditionalInterpreter.cpp
@@ -0,0 +1,30 @@
+
+#include <catch2/catch_test_macros.hpp>
+#include "nodeTester/ConditionalInterpreter.hpp"
+#include "operator/GenericOperator.hpp"
+
+
+using namespace Aidge;
+
+
+
+TEST_CASE("ConditionalInterpreter", "ConditionalInterpreter") {
+
+    SECTION("custom Lambda") {
+
+        const std::string test = " !toto($) == true " ;
+        ConditionalInterpreter conditionalParser = ConditionalInterpreter(test);
+        conditionalParser.insertLambda("toto",+[](NodePtr NodeOp){return false;});
+        std::shared_ptr<Node> nodeOp = GenericOperator("conv", 0, 0, 0, "Gop1");
+
+        bool result = conditionalParser.test(nodeOp);
+        REQUIRE(result == true);
+    }
+
+    SECTION("syntax error") {
+
+        const std::string test = "'A' == 'A' ,&& ";
+        REQUIRE_THROWS_AS( ConditionalInterpreter(test), std::runtime_error);
+  
+    }
+}
\ No newline at end of file
diff --git a/aidge/_Core/tests/Test_ConditionalLexer.cpp b/aidge/_Core/tests/Test_ConditionalLexer.cpp
new file mode 100644
index 00000000..b14500d2
--- /dev/null
+++ b/aidge/_Core/tests/Test_ConditionalLexer.cpp
@@ -0,0 +1,142 @@
+#include <catch2/catch_test_macros.hpp>
+#include "nodeTester/ConditionalLexer.hpp"
+#include <iostream>
+#include <map>
+#include <functional>
+
+using namespace Aidge;
+
+TEST_CASE("nodeTester", "Lexer") {
+    SECTION("RandomGenerateTest") {
+
+        std::map<ConditionalTokenTypes, std::function<std::pair<std::string, std::string>()>> LexerTestMap{
+            {ConditionalTokenTypes::AND,      +[](){return std::pair<std::string, std::string>("&& ","");}},
+            {ConditionalTokenTypes::OR,       +[](){return std::pair<std::string, std::string>("|| ","");}},
+            {ConditionalTokenTypes::EQ,       +[](){return std::pair<std::string, std::string>("== ","");}},
+            {ConditionalTokenTypes::NEQ,      +[](){return std::pair<std::string, std::string>("!= ","");}},
+
+            {ConditionalTokenTypes::KEY,      +[](){return std::pair<std::string, std::string>("A ","A");}},
+
+            {ConditionalTokenTypes::BOOL,     +[](){
+                std::size_t keyLen = (std::rand() % 2);
+                const std::vector<std::string> characters = {"true","false"};
+          
+                return std::pair<std::string, std::string>(characters[keyLen]+" ",characters[keyLen]);}
+            },
+
+            {ConditionalTokenTypes::INTEGER,  +[](){
+                std::size_t keyLen = (std::rand() % 20)+1;
+                const std::string characters = "1234567890";
+                std::size_t randomIndex = std::rand() % characters.size();
+                std::string key;
+                for (std::size_t i = 0; i < keyLen; ++i) {
+                    key += characters[randomIndex];
+                    randomIndex = std::rand() % characters.size();
+                }
+                return std::pair<std::string, std::string>(key+" ",key);}
+            },
+
+            {ConditionalTokenTypes::FLOAT,    +[](){
+                std::size_t keyLen = (std::rand() % 20)+2;
+                const std::string characters = "1234567890";
+                std::size_t randomIndex = std::rand() % characters.size();
+                std::string key;
+                for (std::size_t i = 0; i < keyLen/2; ++i) {
+                    key += characters[randomIndex];
+                    randomIndex = std::rand() % characters.size();
+                }
+                key += ".";
+                for (std::size_t i = 0; i < keyLen/2; ++i) {
+                    key += characters[randomIndex];
+                    randomIndex = std::rand() % characters.size();
+                }
+                return std::pair<std::string, std::string>(key+" ",key);}
+            },
+
+            {ConditionalTokenTypes::STRING,   +[](){
+                std::size_t keyLen = (std::rand() % 20)+1;
+                const std::string characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890 ";
+                std::size_t randomIndex = std::rand() % characters.size();
+                std::string key;
+                for (std::size_t i = 0; i < keyLen; ++i) {
+                    key += characters[randomIndex];
+                    randomIndex = std::rand() % characters.size();
+                }
+
+                return std::pair<std::string, std::string>("'"+key+"' ",key);}
+            },
+
+            {ConditionalTokenTypes::LAMBDA,   +[](){
+
+                std::size_t keyLen = (std::rand() % 20)+1;
+                const std::string characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
+                const std::string Startchar = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+                std::size_t randomIndex = std::rand() % characters.size();
+                std::size_t randomStartIndex = std::rand() % Startchar.size();
+
+                std::string key;
+                key += Startchar[randomStartIndex];
+
+                for (std::size_t i = 0; i < keyLen; ++i) {
+                    key += characters[randomIndex];
+                    randomIndex = std::rand() % characters.size();
+                }
+
+                return std::pair<std::string, std::string>(key+"( ",key);}
+            },
+
+            {ConditionalTokenTypes::ARGSEP,   +[](){return std::pair<std::string, std::string>(", ","");}},
+            {ConditionalTokenTypes::NODE,     +[](){return std::pair<std::string, std::string>("$ ","");}},
+            {ConditionalTokenTypes::LPAREN,   +[](){return std::pair<std::string, std::string>("( ","");}},
+            {ConditionalTokenTypes::RPAREN,   +[](){return std::pair<std::string, std::string>(") ","");}}
+            //{ConditionalTokenTypes::STOP,     +[](){return std::pair<std::string, std::string>("","");}}
+        };
+
+
+        //////////////////
+        //TEST GENERATOR
+        //////////////////
+        const std::size_t numRandomElements = 100;
+        std::vector<std::tuple<ConditionalTokenTypes, std::string>> testVector;
+
+        std::string testString;
+
+        for (std::size_t i = 0; i < numRandomElements; ++i) {
+
+            int randomIndex = std::rand() % LexerTestMap.size();
+            // Get an iterator to the random element in the map
+            auto it = std::next(LexerTestMap.begin(), randomIndex);
+            // Access the random key and lambda value separately using structured binding
+            ConditionalTokenTypes randomKey = it->first;
+
+            std::function<std::pair<std::string, std::string>()> randomValue = it->second;
+            std::pair<std::string, std::string> result = randomValue();
+        
+            testString += result.first;
+            testVector.emplace_back(randomKey, result.second);
+
+       
+        }
+
+        ConditionalLexer conditionalLexer = ConditionalLexer(testString);
+
+        for (std::tuple<ConditionalTokenTypes, std::string> testToken : testVector) {
+            ConditionalTokenTypes tokenToFind = std::get<0>(testToken);
+            std::string lexemToFind = std::get<1>(testToken);
+            std::shared_ptr<Aidge::ConditionalToken> token = conditionalLexer.getNextToken();
+
+
+            std::ostringstream errorMessage;
+            errorMessage << "\n we whant :"<< lexemToFind << "\n we get : "<< token->getLexeme() <<"\n"<< "on \n" << testString << " :\n "  ;
+
+            CAPTURE(errorMessage.str());
+            REQUIRE(token->getLexeme() == lexemToFind);
+            REQUIRE(token->getType() == tokenToFind);
+        }
+        std::shared_ptr<Aidge::ConditionalToken> token = conditionalLexer.getNextToken();
+        REQUIRE(token->getType() == ConditionalTokenTypes::STOP);
+    }
+
+
+}
\ No newline at end of file
diff --git a/aidge/_Core/tests/Test_ConditionalParser.cpp b/aidge/_Core/tests/Test_ConditionalParser.cpp
new file mode 100644
index 00000000..3176e649
--- /dev/null
+++ b/aidge/_Core/tests/Test_ConditionalParser.cpp
@@ -0,0 +1,74 @@
+
+#include <catch2/catch_test_macros.hpp>
+#include "nodeTester/ConditionalParser.hpp"
+
+using namespace Aidge;
+
+    std::string gVal() {
+        int randomValue = std::rand() % 5;
+        switch (randomValue) {
+        case 0:
+            return std::to_string(std::rand() % 101);
+
+        case 1:
+            return std::to_string(std::rand() % 101)+"."+std::to_string(std::rand() % 101);
+
+        case 2:
+             return " 'toto' ";
+        case 3:
+             return " A ";
+
+        case 4:
+             return " A(10) ";
+
+        default:
+             return " true ";
+
+        }
+    }
+
+    std::string gExpr() ;
+    std::string gCmpr() {
+        int randomValue = std::rand() % 3;
+        switch (randomValue) {
+            case 0:
+                return  gVal() + " == " +gVal();
+            case 1:
+                return  "("+ gExpr() +")";
+            default:
+                return  gVal() + " != " +gVal();
+
+        }
+
+
+        return gVal() + " == " +gVal();
+    }
+
+    std::string gExpr() {
+        std::string out = gCmpr();
+        int iterations = std::rand() % 100;
+        for (int i = 0; i < iterations; ++i) {
+            int randomValue = std::rand() % 2;
+            switch (randomValue) {
+                case 0:
+                    return  out +" && " + gCmpr();
+                    break;
+                default:
+                    return  out +" || " + gCmpr();
+                    break;
+            }
+        }
+        return out;
+    }
+
+
+TEST_CASE("ConditionalParser", "ConditionalParser") {
+
+    SECTION("Empty") {
+        for (int i = 0; i < 1000; ++i) {
+            const std::string test = gExpr();
+            ConditionalParser conditionalParser = ConditionalParser(test);
+            std::shared_ptr<Aidge::AstConditionalNode> tree = conditionalParser.parse();
+        }
+    }
+}
\ No newline at end of file
-- 
GitLab