Skip to content
Snippets Groups Projects
Commit 483dcace authored by vincent  lorrain's avatar vincent lorrain
Browse files

[graphRegex] init commit

parent 1b19726b
No related branches found
No related tags found
1 merge request!14Graph regex
Pipeline #31481 failed
Showing
with 2328 additions and 5 deletions
#ifndef __AIDGE_GRAPH_FSM_INTERPRETER_H__
#define __AIDGE_GRAPH_FSM_INTERPRETER_H__
#include <string>
#include <memory>
#include "aidge/utilsParsing/AstNode.hpp"
#include "aidge/graphRegex/GraphRegexTypes.hpp"
#include "aidge/graphRegex/GraphParser.hpp"
#include "aidge/graphRegex/matchFsm/FsmGraph.hpp"
namespace Aidge {
class GraphFsmInterpreter
{
private:
/* data */
GraphParser mParser;
std::size_t mActGroupe;
std::map<std::string,std::shared_ptr<ConditionalInterpreter>> mNodesCondition;
public:
GraphFsmInterpreter(const std::string graphMatchExpr,std::map<std::string,std::shared_ptr<ConditionalInterpreter>> nodesCondition);
virtual ~GraphFsmInterpreter() =default;
std::shared_ptr<FsmGraph> interpret(void);
private:
std::shared_ptr<FsmGraph> visit(std::shared_ptr<AstNode<gRegexTokenTypes>> AstTree);
/**
* @defgroup graphFsmInterpreterF Functions for interpreting AST nodes
* @brief For each node type in the AST, define how build the FsmGraph
*/
/**
* @ingroup graphFsmInterpreterF
* @brief leaf of fsm make the fsm for test one transition
*/
std::shared_ptr<FsmGraph> keyF(std::shared_ptr<AstNode<gRegexTokenTypes>> AstNode);
/**
* @ingroup graphFsmInterpreterF
* @brief combine two fsm of two expression.
*/
std::shared_ptr<FsmGraph> sepF(std::shared_ptr<FsmGraph> leftFsm,std::shared_ptr<FsmGraph> rigthFsm);
/**
* @ingroup graphFsmInterpreterF
* @brief combine two to make a new that match leftFsm next rigthFsm
*/
std::shared_ptr<FsmGraph> nextF(std::shared_ptr<FsmGraph> leftFsm,std::shared_ptr<FsmGraph> rigthFsm);
/**
* @ingroup graphFsmInterpreterF
* @brief make the fsm match +
*/
std::shared_ptr<FsmGraph> qomF(std::shared_ptr<FsmGraph> fsm);
/**
* @ingroup graphFsmInterpreterF
* @brief make the fsm match *
*/
std::shared_ptr<FsmGraph> qzmF(std::shared_ptr<FsmGraph> fsm);
};
}
#endif //__AIDGE_GRAPH_STM_INTERPRETER_H__
\ No newline at end of file
#ifndef __AIDGE_GRAPH_LEXER_H__
#define __AIDGE_GRAPH_LEXER_H__
#include <string>
#include <memory>
#include <regex>
#include <stdexcept> //error
#include <sstream>
#include "aidge/utilsParsing/ParsingToken.hpp"
#include "aidge/graphRegex/GraphRegexTypes.hpp"
namespace Aidge {
class GraphLexer
{
public:
GraphLexer( const std::string gRegexExpressions );
/**
* @brief Get the next token on the gRegexExpressions
* @return ConditionalToken
*/
std::shared_ptr<ParsingToken<gRegexTokenTypes>> getNextToken(void);
/**
* @brief Restart at the start of the gRegexExpressions
*
*/
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();
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 mRegularExpressions;
/**
* @brief The lexer's current position in mConditionalExpressions
*/
std::size_t mPosition;
};
}
#endif //__AIDGE_GRAPH_LEXER_H__
\ No newline at end of file
#ifndef _AIDGE_GRAPH_PARSER_H_
#define _AIDGE_GRAPH_PARSER_H_
#include <memory> // for shared_ptr
#include "aidge/graphRegex/GraphLexer.hpp"
#include "aidge/utilsParsing/AstNode.hpp"
#include "aidge/graphRegex/GraphRegexTypes.hpp"
namespace Aidge{
/**
* @brief this class uses the lexer to create an AST according to a set of gramer rules
*/
class GraphParser{
public:
/**
* @brief AST graph creation function
* @param gRegexExpressions String representing the logical fuction to be performed
*/
GraphParser(const std::string gRegexExpressions);
/**
* @brief AST graph creation function
* @return The AST tree
*/
std::shared_ptr<AstNode<gRegexTokenTypes>> 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(gRegexTokenTypes tokenType);
//TODO TODO
/**
* @ingroup ParsingFunctions
* @brief Function of grammar rules for key : KEY(QOM | QZM)? | CKEY
* @return AST node
*/
std::shared_ptr<AstNode<gRegexTokenTypes>> constructAstExp(void);
/**
* @ingroup ParsingFunctions
* @brief Function of grammar rules for sequence : seq :exp (NEXT seq)*
* @return AST node
*/
std::shared_ptr<AstNode<gRegexTokenTypes>> constructAstSeq(void);
/**
* @ingroup ParsingFunctions
* @brief Function of grammar rules for domain : (seq NEXT domain)? | LPAREN domain RPAREN (QOM | QZM) (NEXT domain)?
* @return AST node
*/
std::shared_ptr<AstNode<gRegexTokenTypes>> constructAstDomain(void);
/**
* @ingroup ParsingFunctions
* @brief Function of grammar rules for multiple exepresion : allExpr: domain (SEP allExpr)*
* @return AST node
*/
std::shared_ptr<AstNode<gRegexTokenTypes>> constructAstAllExpr(void);
/**
* @brief The actual token in the parce
*/
std::shared_ptr<ParsingToken<gRegexTokenTypes>> mCurrentToken;
/**
* @brief The lexem use
*/
GraphLexer mLexer;
};
}
#endif //_AIDGE_GRAPH_PARSER_H_
#ifndef __AIDGE_GREGEX_TOKEN_TYPES_H__
#define __AIDGE_GREGEX_TOKEN_TYPES_H__
namespace Aidge {
/**
* @brief enum for all types of token use in the of the regex
* 7-5 type
* 4-0 id
*/
enum class gRegexTokenTypes
{
NEXT = (1 << 4)+1, /**< -> */
QOM = (1 << 5)+1, /**< + */
QZM = (1 << 5)+2, /**< * */
KEY = (1 << 6)+2, /**< [A-Za-z_0-9]+ */
CKEY = (1 << 6)+1, /**< [A-Za-z_0-9]+#[0-9]* */
SEP = (1<<7) +1, /**< \( */
LPAREN = (1<<7) +2, /**< \( */
RPAREN = (1<<7) +3, /**< \) */
STOP = 0,
};
}
#endif //__AIDGE_GREGEX_TOKEN_TYPES_H__
\ No newline at end of file
#ifndef __AIDGE_FSM_EDGE_H__
#define __AIDGE_FSM_EDGE_H__
#include <memory>
#include <set>
#include <string>
//#include "graphRegex/matchFsm/FsmNode.hpp"
#include "aidge/nodeTester/ConditionalInterpreter.hpp"
//#include "graphRegex/matchFsm/FsmRunTimeContext.hpp"
namespace Aidge{
class FsmNode;
class FsmRunTimeContext;
struct EdgeTestResult {
bool success;
std::set<NodePtr> node;
};
/**
* @brief virtual class use test the node on the node to validate
*/
class FsmEdge: public std::enable_shared_from_this<FsmEdge>
{
private:
/**
* @brief the relative position to this test relative to all the const key
* firse is common id , segond is the relative position
*/
std::map<size_t,int> mRelativePos;
/**
* @brief the ptr on the source node
*/
std::shared_ptr<FsmNode> mNodeSource;
/**
* @brief the ptr on the dest node
*/
std::shared_ptr<FsmNode> mNodeDest;
public:
FsmEdge(std::shared_ptr<FsmNode> source,std::shared_ptr<FsmNode> dest, const std::shared_ptr<ConditionalInterpreter> toTest);
virtual ~FsmEdge() =default;
/**
* @brief test is the validation of the node , it must be deffine for all types of edge
* it takes as argument an FSM traversal context and returns a set of next nodes
* @return set of next node or nullptr if not next
*/
virtual const EdgeTestResult test(const std::shared_ptr<FsmRunTimeContext> stmContext) =0;
/**
* @brief test is the egde test a common node
* @return true if is a common
*/
virtual bool isCommon(void);
/**
* @brief get the Common idx of the common test in this edge (if is a common edge)
* @return idx of the common
*/
virtual size_t getCommonIdx(void);
/**
* @brief get the relative postion to the common node deffine in this edge
* @return map
*/
const std::map<size_t,int>& getRelative(void);
/**
* @brief add new relative position
*/
void updateRelative( const std::map<size_t,int>& relativePos );
/**
* @brief get source FsmNode
* @return FsmNode
*/
std::shared_ptr<FsmNode> getSourceNode(void);
/**
* @brief set a new source to the edge
* @return FsmNode
*/
void reSetSouceNode(const std::shared_ptr<FsmNode>& newSource);
/**
* @brief get dest FsmNode
* @return FsmNode
*/
std::shared_ptr<FsmNode> getDestNode(void);
/**
* @brief set a new dest to the edge
* @return FsmNode
*/
void reSetDestNode(const std::shared_ptr<FsmNode>& newDest);
/**
* @brief propagate the edge mRelativePos to the others Edge and recalcul the relative position
*/
void propagateRelativePos(void);
/**
* @brief test to make on the node to validate
* @see ConditionalInterpreter
*/
const std::shared_ptr<ConditionalInterpreter> mToTest;
};
/**
* @brief class spesialisation for not commun node (node that must be match one Unique) transition
*/
class FsmEdgeUnique:public FsmEdge
{
public:
FsmEdgeUnique(std::shared_ptr<FsmNode> source,std::shared_ptr<FsmNode> dest, const std::shared_ptr<ConditionalInterpreter> toTest);
//~FsmEdgeUnique() override {}
const EdgeTestResult test(const std::shared_ptr<FsmRunTimeContext> stmContext) override;
};
/**
* @brief class spesialisation for commun node transition
* @see FsmEdge
*/
class FsmEdgeCommon:public FsmEdge
{
private:
/**
* @brief the map that defind the ralation between the commonKey find by the lexer and a unique id use to refer to the common node
*/
static std::map<std::string,int> mCommonIdxMap;
/**
* @brief the common id test in this transition
*/
int mCommonIdx;
public:
/**
* @brief constructor commun node ,
* @details during construction,
* the node key found by the lexer is converted to a unique id and the relative positions are updated.
*/
FsmEdgeCommon(std::shared_ptr<FsmNode> source,std::shared_ptr<FsmNode> dest, const std::shared_ptr<ConditionalInterpreter> toTest, const std::string commonKey);
// ~FsmEdgeCommon() override {}
const EdgeTestResult test(const std::shared_ptr<FsmRunTimeContext> stmContext) override;
bool isCommon(void) override;
};
/**
* @brief class spesialisation for ref transition
* @see FsmEdge
*/
class FsmEdgeRef:public FsmEdge
{
private:
/**
* @brief the id of one common node that we use as an anchor
*/
const int mRefCommonIdx;
/**
* @brief the delta in terme of child or parent refer to the anchor
*/
const int mdeltaCommonIdx;
public:
FsmEdgeRef(std::shared_ptr<FsmNode> source,std::shared_ptr<FsmNode> dest, const size_t refCommonIdx,const int deltaCommonIdx);
//~FsmEdgeRef() override {}
const EdgeTestResult test(const std::shared_ptr<FsmRunTimeContext> stmContext) override;
};
/**
* @brief class spesialisation for ref empty transition
* @see FsmEdge
*/
class FsmEdgeEmpty:public FsmEdge
{
public:
FsmEdgeEmpty(std::shared_ptr<FsmNode> source,std::shared_ptr<FsmNode> dest);
//~FsmEdgeEmpty() override {}
const EdgeTestResult test(const std::shared_ptr<FsmRunTimeContext> stmContext) override;
};
////////////////////////
// FACTORY
////////////////////////
enum class FsmEdgeTypes {
EMPTY = 0,
REF,
COMMON,
UNIQUE
};
class FsmEdgeFactory {
public:
/**
* @brief factory for making edge and read the info in the lexeme of the token
* @param source source node of the edge
* @param dest Dest node of the edge
* @param type type of the edge
* @param lexeme the additional information to build the edge
* @return s prt of the edge
*/
static std::shared_ptr<FsmEdge> make(std::shared_ptr<FsmNode> source, std::shared_ptr<FsmNode> dest,
FsmEdgeTypes type,std::map<std::string, std::shared_ptr<ConditionalInterpreter>> allTest,
const std::string lexeme = "");
};
}
#endif //__AIDGE_FSM_EDGE_H__
\ No newline at end of file
#ifndef __AIDGE_FSM_GRAPH_H__
#define __AIDGE_FSM_GRAPH_H__
#include <set>
#include <vector>
#include <memory>
#include <stdexcept> //error
#include "aidge/graphRegex/matchFsm/FsmNode.hpp"
#include "aidge/graphRegex/matchFsm/FsmEdge.hpp"
#include "aidge/graphRegex/matchFsm/MatchResult.hpp"
namespace Aidge{
class FsmGraph
{
private:
std::set<std::size_t> mAllOrigine;
std::set<std::shared_ptr<FsmEdge>> mEdges;
public:
FsmGraph(/* args */);
virtual ~FsmGraph() = default;
std::vector<std::shared_ptr<MatchResult>> test(std::vector<NodePtr>& StartNodes);
const std::set<std::shared_ptr<FsmEdge>>& getEdge(void);
/**
* @brief add edge in the graph, as FsmEdge know the source and dest FsmNode these nodes are also add to the graph
*/
void addEdge(std::shared_ptr<FsmEdge> edge);
/**
* @brief get the liste of the starting states
* @details we need to use a vector because the order of the nodes is important for start node initialization \ref test()
*/
const std::vector<std::shared_ptr<FsmNode>> getStartNodes(void);
/**
* @brief get the set of the valide states
* @return set of valide state
*/
const std::set<std::shared_ptr<FsmNode>> getValidNodes(void);
/**
* @brief get the set of all the node in the graph
* @return set of all nodes
*/
const std::set<std::shared_ptr<FsmNode>> getNodes(void);
/**
* @brief set a groupe idx for all the nodes in the graph
*/
void setGroupe(std::size_t groupeIdx);
/**
* @brief make the union beteen this graph and an input graph
* @param fsmGraph graph to union
*/
void unionG(const std::shared_ptr<FsmGraph> fsmGraph);
/**
* @brief make the union beteen this graph and an input graph and merge the valide state to the start state
* @param fsmGraph graph to merge
*/
void mergeOneStartOneValid(const std::shared_ptr< FsmGraph> fsmGraph);
/**
* @brief get the number of sub FSM
* @return number of sub Fsm
*/
std::size_t getNbSubFsm(void);
/**
* @brief increment the origine of all node in the graph
* @param incr the incrémentation value
*/
void incOrigineAllNodeBy(std::size_t incr);
private:
/**
* @brief merge tow node of the graph
* @param node
*/
void _mergeNode(std::shared_ptr<FsmNode> source,std::shared_ptr<FsmNode> dest);
};
}
#endif //__AIDGE_FSM_GRAPH_H__
\ No newline at end of file
#ifndef __AIDGE_FSM_NODE_H__
#define __AIDGE_FSM_NODE_H__
#include <set>
#include <vector>
#include <memory>
//#include "graphRegex/matchFsm/FsmEdge.hpp"
//#include "graphRegex/matchFsm/FsmRunTimeContext.hpp"
namespace Aidge{
// Forward declaration of the class defined in graphRegex/matchFsm/FsmEdge.hpp
class FsmEdge;
struct EdgeTestResult;
class FsmRunTimeContext;
//------------------------------------------------------------------------------
// MAY BE IN UTILE
template <typename T>
struct lex_compare {
bool operator() (const std::weak_ptr<T> &lhs, const std::weak_ptr<T> &rhs)const {
auto lptr = lhs.lock(), rptr = rhs.lock();
if (!rptr) return false; // nothing after expired pointer
if (!lptr) return true;
return lptr < rptr;
}
};
/**
* @brief is a node in the FSM graph, it's a state in the FSM
* @details a state can be and/or :
* - a valide state, the match is valide if it stop on this edge
* - a start state , the match start on this state
* The state is also define by this origine (is the unique id of it's expretion )
* and it's groupe (for inner expression TODO)
*/
class FsmNode : public std::enable_shared_from_this<FsmNode>
{
private:
/**
* @brief the edge of the node
* @details the edge have a shared ref to the node so we use weak ref
*/
std::set<std::weak_ptr<FsmEdge>,lex_compare<FsmEdge>> mEdges;
/**
* @brief the parent of the node
*/
std::set<std::weak_ptr<FsmNode>,lex_compare<FsmNode>> mParents;
std::size_t mOrigineStm = 0;
std::size_t mGroupeStm = 0;
bool mIsAValid;
bool mIsAStart;
public:
FsmNode(bool isAValid,bool isAStart );
virtual ~FsmNode() = default;
/**
* @brief use to MAG the actual context , and return all the posible new context
* @details one input context can generate a multitude of contexts because a graph node
* can have more than one child, and each traversal possibility is a new context.
* @param actContext the actual context
* @return A vector of all the new context
*/
const std::vector<std::shared_ptr<FsmRunTimeContext>> test( std::shared_ptr<FsmRunTimeContext>);
std::size_t getOrigine(void);
void incOrigine(std::size_t inc);
void rmEdge(std::shared_ptr<FsmEdge>);
void addEdge(std::shared_ptr<FsmEdge>);
const std::set<std::shared_ptr<FsmNode>> getChildNodes(void);
const std::set<std::weak_ptr<FsmNode>,lex_compare<FsmNode>> getParentNodes(void);
const std::set<std::weak_ptr<FsmEdge>,lex_compare<FsmEdge>> getEdges(void);
void setGroupe(std::size_t groupeIdx);
bool isValid(void);
bool isStart(void);
void unValid(void);
void valid(void);
void unStart(void);
void start(void);
void addParent(std::shared_ptr<FsmNode>);
void rmParent(std::shared_ptr<FsmNode>);
};
}
#endif //__AIDGE_FSM_NODE_H__
\ No newline at end of file
#ifndef __AIDGE_FSM_RUN_TIME_CONTEXT_H__
#define __AIDGE_FSM_RUN_TIME_CONTEXT_H__
#include <memory>
#include <vector>
#include <set>
#include <algorithm>
//#include "graphRegex/matchFsm/FsmNode.hpp"
#include "aidge/nodeTester/ConditionalInterpreter.hpp"
#include "aidge/graph/Node.hpp"
namespace Aidge{
class FsmNode;
class FsmNode;
/**
* @brief a class used to save the execution context of state machines, that is the actual state in the FSM, the actual node in the graph
* all node that have been Validate,Rejecte or Considered common
*/
class FsmRunTimeContext
{
private:
/**
* @brief the list of node rejected for all the context
*/
static std::vector<std::set<NodePtr>> mRejectedNodes;
/**
* @brief the actual state of this Context (where it's in the FSM graph)
*/
std::shared_ptr<FsmNode> mActState;
/**
* @brief the actual node of this Context (where it's in the graph)
*/
NodePtr mActOpNode;
/**
* @brief the map of the node consider as common and the common ID
* @details we need to store what node it's consider as common because of the end
* resolution of the matching, all node consider as common need to be the same in all context
*/
std::map<NodePtr,std::size_t> mCommonNodes;
/**
* @brief the map of the node that as been valid in this context , and the test that valide the node
*/
std::map<std::shared_ptr<ConditionalInterpreter>,std::set<NodePtr>> mValidNodes;
/**
* @brief the index in the rejected node of this context
*/
std::size_t mLocalIdxRejeced;
public:
/**
* @brief constructor
* @param actState the actual state in the FSM
* @param actOpNode the actual node in the graph
* @param idxRejeced the idx in the global regected node vector init -1 as sentinel value of undefind
*/
FsmRunTimeContext(std::shared_ptr<FsmNode> actState ,NodePtr actOpNode ,std::size_t idxRejeced =std::numeric_limits<std::size_t>::max() );
FsmRunTimeContext(std::shared_ptr<FsmRunTimeContext> fsmRunTime);
FsmRunTimeContext(std::shared_ptr<FsmRunTimeContext> fsmRunTime,std::shared_ptr<FsmNode> actState ,NodePtr actOpNode );
virtual ~FsmRunTimeContext()=default;
/**
* @defgroup FsmRunTimeContextRejected Function for managing rejected nodes
*/
/**
* @ingroup FsmRunTimeContextRejected
* @brief Add a node as rejected in this context
*/
void addRejectedNode(NodePtr node);
/**
* @ingroup FsmRunTimeContextRejected
* @brief get the rejected nodes of this context
*/
std::set<NodePtr> getRejectedNodes(void);
/**
* @defgroup FsmRunTimeContextTest Function for test the context
*/
/**
* @ingroup FsmRunTimeContextTest
* @brief test if the actual state is valide
* @return bool
*/
bool isOnValidState(void);
/**
* @ingroup FsmRunTimeContextTest
* @brief test if the node is considered as common in this context
* @param node node to test
* @return bool
*/
bool isCommonDefined(NodePtr node);
/**
* @ingroup FsmRunTimeContextTest
* @brief test if has already validated in this context
* @param node node to test
* @return bool
*/
bool isAlreadyValid(NodePtr node);
/**
* @ingroup FsmRunTimeContextTest
* @brief test if this context is compatible with an others
* @details to say that two contexts are compatible is to check :
* that the contexts do not validate the same nodes (other than the common ones)
* and that the common ones have the same idx
* @param fsmContext the others context
* @return bool
*/
bool areCompatible(std::shared_ptr<FsmRunTimeContext> fsmContext);
/**
* @ingroup FsmRunTimeContextTest
* @brief test if this context is strictly equal with an others
* @param fsmContext the others context
* @return bool
*/
bool areEqual(std::shared_ptr<FsmRunTimeContext> fsmContext);
/**
* @defgroup FsmRunTimeContextSet Function set context
*/
void setCommon(NodePtr node,std::size_t commonIdx);
void setValid(NodePtr node,std::shared_ptr<ConditionalInterpreter> tag);
/**
* @defgroup FsmRunTimeContextGet Function get context
*/
/**
* @ingroup FsmRunTimeContextGet
* @brief get the sub idx state
* @return bool
*/
std::size_t getSubStmId(void);
NodePtr getCommonNodeFromIdx(std::size_t commonIdx);
std::size_t getCommonNodeIdx(NodePtr node);
std::set<NodePtr> getCommonNodes(void);
std::map<NodePtr,std::size_t> getCommon(void);
std::set<NodePtr> getValidNodes(void);
std::set<NodePtr> getValidNodesNoCommon(void);
std::map<std::shared_ptr<ConditionalInterpreter>,std::set<NodePtr>> getValid(void);
NodePtr getActNode(void);
std::shared_ptr<FsmNode> getActState(void);
/**
* @defgroup FsmRunTimeContextMem
*/
void rst(void);
};
}
#endif //__AIDGE_FSM_RUN_TIME_CONTEXT_H__
\ No newline at end of file
#ifndef __AIDGE_MATCH_RESULT_H__
#define __AIDGE_MATCH_RESULT_H__
#include <memory>
#include "aidge/graphRegex/matchFsm/FsmRunTimeContext.hpp"
namespace Aidge{
/**
* @brief class that old the result of a matching
* give acess to all node ant there tag in the expression
*/
class MatchResult
{
private:
/* data */
public:
MatchResult(std::shared_ptr<FsmRunTimeContext> contexte);
virtual ~MatchResult() = default;
/**
* @brief get the set of the node match for une expression
* @return the set of node of the graph that corresponding to an expression
*/
std::set<NodePtr> getNodes(void);
};
}
#endif //__AIDGE_MATCH_RESULT_H__
\ No newline at end of file
#ifndef _AIDGE_CONDITIONAL_DATA_H_
#define _AIDGE_CONDITIONAL_DATA_H_
#include <vector>
#include <string>
#include <stdexcept> //error
#include <memory>
#include <map>
namespace Aidge{
/////////////////////////
// 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) {
//make sure that the old value is free
deleteValue();
value = std::make_unique<ConditionalValue<T>>(newValue);
type = &typeid(T);
}
/**
* @brief get the actual value
* @details recaste the value to the templaited type and checks that the conversion type is compatible with type
* @tparam the type of the return value
* @return the value
*/
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
#ifndef _AIDGE_CONDITIONAL_INTERPRETER_H_
#define _AIDGE_CONDITIONAL_INTERPRETER_H_
#include "aidge/nodeTester/ConditionalParser.hpp"
#include "aidge/nodeTester/ConditionalData.hpp"
#include <memory> // for shared_ptr
#include <unordered_map>
#include <functional>
#include "aidge/graph/Node.hpp"
#include <sstream>
namespace Aidge{
//////////////////////////////
//
/////////////////////////////
/**
* @brief class used to register any lambda function without context,
* it encapsulates the source lambda in a lambda which takes as argument ConditionalData* which are any type.
* @see ConditionalData
*/
class ConditionalRegisterFunction {
//////////////////////////
//Safe recaste
//////////////////////////
/**
* @brief recaste the ConditionalData* to the argument type of the lambda
* @tparam T type of the lambda argument
* @see ConditionalData
*/
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() );
}
}
/**
* @brief recaste the output of the lambda to a ConditionalData*
* @tparam T type of the lambda return
* @see 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...>{});
}
/**
* @brief Converts a std::function 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(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
// ////////////////
/**
* @brief this class interprets AST to generate a test on a graph node. For each AST node,
* it generates an interpretation and registers lambda functions that can be used in the test expression.
* there are two lambda control mechanisms:
* - A cpp mechanism which allows any lambda to be inserted into the constructor that use templaite
* - A user mechanism limited to lambda bool(NodePtr)
* @see ConditionalParser use to get the AST
*/
class ConditionalInterpreter
{
private:
/**
* @brief the AST generate by the Parser
* @see ConditionalParser
*/
std::shared_ptr<AstNode<ConditionalTokenTypes>> mTree;
/**
* @brief the registery for the lambda fuction
* @see ConditionalRegisterFunction
*/
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
* @details the AST is visit using \ref visit() whith the $ init whit the nodeOp
* @return bool the match node has the initialized expresion
* @see visit() This function uses the visit() function to perform the evaluation.
*/
bool test( const NodePtr nodeOp);
/**
* @brief Interface for inserting custom lambda bool(NodePtr) functions in AST interpretation,
* it will be available in the ConditionalExpressions expretion as : key($)
* @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<AstNode<ConditionalTokenTypes>>& 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<AstNode<ConditionalTokenTypes>>& node);
/**
* @ingroup ASTnodeInterpreterF
* @brief Converted the lexeme to a float and to ConditionalData*
*/
std::vector<ConditionalData*> fStrToFloat(const std::shared_ptr<AstNode<ConditionalTokenTypes>>& node);
/**
* @ingroup ASTnodeInterpreterF
* @brief Converted the lexeme to a str and to ConditionalData*
*/
std::vector<ConditionalData*> fStrToStr(const std::shared_ptr<AstNode<ConditionalTokenTypes>>& 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_
/**
* @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>
#include "aidge/nodeTester/ConditionalTypes.hpp"
#include "aidge/utilsParsing/ParsingToken.hpp"
namespace Aidge{
class ConditionalLexer
{
public:
ConditionalLexer( const std::string ConditionalExpressions );
/**
* @brief Get the next token on the ConditionalExpressions
* @return ParsingToken<ConditionalTokenTypes>
*/
std::shared_ptr<ParsingToken<ConditionalTokenTypes>> 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
#ifndef _AIDGE_CONDITIONAL_PARSER_H_
#define _AIDGE_CONDITIONAL_PARSER_H_
#include <memory> // for shared_ptr
#include "aidge/nodeTester/ConditionalLexer.hpp"
#include "aidge/nodeTester/ConditionalTypes.hpp"
#include "aidge/utilsParsing/ParsingToken.hpp"
#include "aidge/utilsParsing/AstNode.hpp"
namespace Aidge{
const std::map<ConditionalTokenTypes, std::size_t> ConditionalPrec{
{ConditionalTokenTypes::AND,2},
{ConditionalTokenTypes::OR,1}
};
using ASTNodeCh = std::vector<std::shared_ptr<AstNode<ConditionalTokenTypes>>>;
/**
* @brief this class uses the lexer to create an AST according to a set of gramer rules
*/
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<AstNode<ConditionalTokenTypes>> 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<AstNode<ConditionalTokenTypes>> constructAstVal(void);
/**
* @ingroup ParsingFunctions
* @brief Function of grammar rules for comparison : val (EQ|NEQ) val | LPAREN expr RPAREN
* @return AST node
*/
std::shared_ptr<AstNode<ConditionalTokenTypes>> 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<AstNode<ConditionalTokenTypes>> constructAstLambda(void);
/**
* @ingroup ParsingFunctions
* @brief Function of grammar rules for a expresion : cmpr ((AND | OR) cmpr)*
* @return AST node
*/
std::shared_ptr<AstNode<ConditionalTokenTypes>> constructAstExpr(std::size_t precLimit = 0);
/**
* @brief The actual token in the parce
*/
std::shared_ptr<ParsingToken<ConditionalTokenTypes>> mCurrentToken;
/**
* @brief The lexem use
*/
ConditionalLexer mLexer;
};
}
#endif //_AIDGE_CONDITIONAL_PARSER_H_
#ifndef _AIDGE_CONDITIONAL_TYPES_H_
#define _AIDGE_CONDITIONAL_TYPES_H_
namespace Aidge{
/**
* @brief enum for all types of token use in the parsing
* 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 , /**< [A-Za-z][A-Za-z0-9_]* */
INTEGER = (1 << 6) +2 , /**< [0-9]+ */
FLOAT = (1 << 6) +3 , /**< [0-9]+\.[0-9]* */
STRING = (1 << 6) +4 , /**< \'.*\' */
BOOL = (1 << 6) +5 , /**< true|false */
NODE = (1 << 6) +6 , /**< \$ */
LAMBDA = (1 << 6) +7 , /**< [A-Za-z][A-Za-z0-9_]*\( */
ARGSEP = (1<<7) +1, /**< , */
LPAREN = (1<<7) +2, /**< \( */
RPAREN = (1<<7) +3, /**< \) */
STOP = 0,
};
}
#endif
\ No newline at end of file
......@@ -12,11 +12,11 @@
namespace Aidge{
template <typename EnumType>
class AstNode: public std::enable_shared_from_this<AstNode>
class AstNode: public std::enable_shared_from_this<AstNode<EnumType>>
{
static_assert(std::is_enum<EnumType>::value, "AstNode EnumType must be an enum type");
public:
AstNode(std::shared_ptr<ParsingToken<EnumType>> token,std::vector<std::shared_ptr<AstNode>> child ={}):mToken(token),mChild(child){}
AstNode(std::shared_ptr<ParsingToken<EnumType>> token,std::vector<std::shared_ptr<AstNode<EnumType>>> child ={}):mToken(token),mChild(child){}
/**
* @brief get the type of the token
* @return the type
......
......@@ -4,10 +4,12 @@
#include <string>
#include <type_traits>
#include <sstream> // Include the necessary header
namespace Aidge{
template <typename EnumType>
class ParsingToken: public std::enable_shared_from_this<ParsingToken>
class ParsingToken: public std::enable_shared_from_this<ParsingToken<EnumType>>
{
static_assert(std::is_enum<EnumType>::value, "ParsingToken EnumType must be an enum type");
public:
......@@ -16,7 +18,7 @@ namespace Aidge{
* @param type one of the token type
* @param lexeme String representing aditional information of the token
*/
ParsingToken(const EnumType type , const std::string lexeme )mLexeme(lexeme),mType(type){}
ParsingToken(const EnumType type , const std::string lexeme ):mLexeme(lexeme),mType(type){}
/**
* @brief get the lexeme
......@@ -39,7 +41,10 @@ namespace Aidge{
* @brief copy the token
* @return deep copy of the token
*/
std::shared_ptr<Aidge::ParsingToken> copy();
std::shared_ptr<ParsingToken> copy(){
auto newToken = std::make_shared<ParsingToken<EnumType>>(mType,mLexeme);
return newToken;
}
//TODO
std::ostringstream rep(void){
......@@ -47,6 +52,7 @@ namespace Aidge{
out << " Token (" << mLexeme <<")" << "\n";
return out;
}
private:
/**
......
#include "aidge/graphRegex/GraphFsmInterpreter.hpp"
using namespace Aidge;
GraphFsmInterpreter::GraphFsmInterpreter(const std::string graphMatchExpr,std::map<std::string,std::shared_ptr<ConditionalInterpreter>> nodesCondition):mParser(graphMatchExpr){
mActGroupe = 0;
mNodesCondition = nodesCondition;
}
std::shared_ptr<FsmGraph> GraphFsmInterpreter::interpret(void){
mActGroupe = 0;
std::shared_ptr<AstNode<gRegexTokenTypes>> tree = mParser.parse();
return visit(tree);
}
std::shared_ptr<FsmGraph> GraphFsmInterpreter::visit(std::shared_ptr<AstNode<gRegexTokenTypes>> AstTree){
std::vector<std::shared_ptr<AstNode<gRegexTokenTypes>>> nextAstNodes = AstTree->getChilds();
if(AstTree->getType() == gRegexTokenTypes::SEP){
return sepF(visit(nextAstNodes[0]),visit(nextAstNodes[1]));
}else if(AstTree->getType() == gRegexTokenTypes::NEXT){
return nextF(visit(nextAstNodes[0]),visit(nextAstNodes[1]));
}else if(AstTree->getType() == gRegexTokenTypes::QOM){
return qomF(visit(nextAstNodes[0]));
}else if(AstTree->getType() == gRegexTokenTypes::QZM){
return qzmF(visit(nextAstNodes[0]));
}else if(AstTree->getType() == gRegexTokenTypes::KEY || AstTree->getType() == gRegexTokenTypes::CKEY){
return keyF(AstTree);
}else if(AstTree->getType() == gRegexTokenTypes::LPAREN){
mActGroupe += 1;
std::shared_ptr<FsmGraph> out = visit(nextAstNodes[0]);
mActGroupe -= 1;
return out;
}else{
throw std::logic_error("visit Bad token type" );
}
}
std::shared_ptr<FsmGraph> GraphFsmInterpreter::keyF(std::shared_ptr<AstNode<gRegexTokenTypes>> AstNode){
std::shared_ptr<FsmNode> start = std::make_shared<FsmNode>(false,true);
std::shared_ptr<FsmNode> valid = std::make_shared<FsmNode>(true,false);
std::shared_ptr<FsmGraph> graph = std::make_shared<FsmGraph>();
std::shared_ptr<FsmEdge> edge;
if(AstNode->getType() == gRegexTokenTypes::CKEY){
edge = FsmEdgeFactory::make(start,valid,FsmEdgeTypes::COMMON,mNodesCondition,AstNode->getValue());
}else if (AstNode->getType() == gRegexTokenTypes::KEY)
{
edge = FsmEdgeFactory::make(start,valid,FsmEdgeTypes::UNIQUE,mNodesCondition,AstNode->getValue());
}else{
throw std::logic_error("keyF Bad in AST" );
}
graph->addEdge(edge);
graph->setGroupe(mActGroupe);
return graph;
}
std::shared_ptr<FsmGraph> GraphFsmInterpreter::sepF(std::shared_ptr<FsmGraph> leftFsm,std::shared_ptr<FsmGraph> rigthFsm){
size_t idxLeft = leftFsm->getNbSubFsm();
rigthFsm->incOrigineAllNodeBy(idxLeft);
leftFsm->unionG(rigthFsm);
//the rigthFsm is no longer usfull
return leftFsm;
}
std::shared_ptr<FsmGraph> GraphFsmInterpreter::nextF(std::shared_ptr<FsmGraph> leftFsm,std::shared_ptr<FsmGraph> rigthFsm){
/*
combine the 2 Graph
all valid node of A are merge with Start B, Start B is un Start
update the relative reference
A B
SA -> VA + SB -> VB
A B
SA -> q -> VB
*/
leftFsm->mergeOneStartOneValid(rigthFsm);
//the rigthFsm is no longer usfull
return leftFsm;
}
std::shared_ptr<FsmGraph> GraphFsmInterpreter::qomF(std::shared_ptr<FsmGraph> fsm){
/*
+
valid node is connect to the child of Start with the same edge condition
A
S -> V
A
S -> V
(E|R)
V -> S
*/
std::vector<std::shared_ptr<FsmNode>> allStart = fsm->getStartNodes();
std::set<std::shared_ptr<FsmNode>> allValid = fsm->getValidNodes();
std::shared_ptr<FsmEdge> edge;
if(allStart.size() != 1){
throw std::logic_error("qomF Bad in AST" );
}
for(auto start : allStart ){
for(auto edgeStart :start->getEdges() ){
if (auto sharedEdge = edgeStart.lock()) {
const std::map<size_t, int> commonRef = sharedEdge->getRelative();
bool haveCommon = !commonRef.empty();
for(auto valid : allValid){
if(haveCommon){
/*
the // quantif case
get the go back and make a lexeme id(number)
we need to go back to the ref delta min #TODO
*/
bool hasMinRef = false;
std::pair<size_t, int> minRef;
for (const auto& entry : commonRef) {
if (!hasMinRef || std::abs(minRef.second) > std::abs(entry.second)) {
hasMinRef = true;
minRef = entry;
}
}
std::stringstream lexem;
lexem << "(" << minRef.first << ", " << minRef.second << ")";
edge = FsmEdgeFactory::make(valid,start,FsmEdgeTypes::REF,mNodesCondition, lexem.str());
}else{
/*
the sequensial quantif case
no reference to common
*/
edge = FsmEdgeFactory::make(valid,start,FsmEdgeTypes::EMPTY,mNodesCondition,"");
}
fsm->addEdge(edge);
}
}else{
throw std::runtime_error("edgeStart weak pointer is expired" );
}
}
}
return fsm;
}
std::shared_ptr<FsmGraph> GraphFsmInterpreter::qzmF(std::shared_ptr<FsmGraph> fsm){
/*
qomf and a bypass empty start to valide
*/
fsm = qomF(fsm);
std::vector<std::shared_ptr<FsmNode>> allStart = fsm->getStartNodes();
std::set<std::shared_ptr<FsmNode>> allValid = fsm->getValidNodes();
std::shared_ptr<FsmEdge> edge;
if(allStart.size() != 1){
throw std::logic_error("qzmF Bad in AST" );
}
for(auto start : allStart ){
for(auto valid : allValid){
edge = FsmEdgeFactory::make(start,valid,FsmEdgeTypes::EMPTY,mNodesCondition,"");
fsm->addEdge(edge);
}
}
return fsm;
}
\ No newline at end of file
#include "aidge/graphRegex/GraphLexer.hpp"
using namespace Aidge;
GraphLexer::GraphLexer( const std::string gRegexExpressions ):
mRegularExpressions(gRegexExpressions){
mPosition = 0;
}
std::shared_ptr<ParsingToken<gRegexTokenTypes>> GraphLexer::getNextToken(void){
std::string currentChars = "";
while (mPosition < mRegularExpressions.length())
{
//erase all space
if (mRegularExpressions[mPosition] != ' ')
{
currentChars += mRegularExpressions[mPosition];
}
else
{
mPosition++;
continue;
}
/////
// const lent token
/////
if (std::regex_match(currentChars,std::regex("\\->")))// the next TOKEN
{
mPosition++;
return std::make_shared<ParsingToken<gRegexTokenTypes>>(gRegexTokenTypes::NEXT,"");
}
else if (std::regex_match(currentChars,std::regex("\\*")))// the * TOKEN
{
mPosition++;
return std::make_shared<ParsingToken<gRegexTokenTypes>>(gRegexTokenTypes::QZM,"");
}
else if (std::regex_match(currentChars,std::regex("\\+")))// the + TOKEN
{
mPosition++;
return std::make_shared<ParsingToken<gRegexTokenTypes>>(gRegexTokenTypes::QOM,"");
}
else if (std::regex_match(currentChars,std::regex("\\(")))// the LPAREN TOKEN
{
mPosition++;
return std::make_shared<ParsingToken<gRegexTokenTypes>>(gRegexTokenTypes::LPAREN,"");
}
else if (std::regex_match(currentChars,std::regex("\\)")))// the RPAREN TOKEN
{
mPosition++;
return std::make_shared<ParsingToken<gRegexTokenTypes>>(gRegexTokenTypes::RPAREN,"");
}
//
else if (std::regex_match(currentChars,std::regex(";")))// the SEP TOKEN
{
//test if the last sep
//std::string subStr = mRegularExpressions.substr(mPosition);
mPosition++;
return std::make_shared<ParsingToken<gRegexTokenTypes>>(gRegexTokenTypes::SEP,"");
}
/////
//unconst lent token
/////
else if (std::regex_match(currentChars,std::regex("[A-Za-z_0-9]")))// the KEY or CKEY
{
//read all the key
bool isCKey = false;
std::regex keyRegex("[A-Za-z_0-9]+");
std::regex cKeyRegex("[A-Za-z_0-9]+\\#[0-9]*");
while ( mPosition < mRegularExpressions.length()) {
if(!std::regex_match(currentChars,keyRegex) && !std::regex_match(currentChars,cKeyRegex))
{
currentChars.pop_back(); //the last char is the problemes
break;
}
else if (std::regex_match(currentChars,cKeyRegex)){
isCKey = true;
}
mPosition++;
if (mPosition < mRegularExpressions.length()) currentChars += mRegularExpressions[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 == mRegularExpressions.length()-1)
{
if (!std::regex_match(currentChars,keyRegex) && !std::regex_match(currentChars,cKeyRegex))
{
throw badTokenError(currentChars,mPosition);
}
//mPosition++; // we stop all by going pos > lengt
}
if (isCKey){
return std::make_shared<ParsingToken<gRegexTokenTypes>>(gRegexTokenTypes::CKEY,currentChars);
} else{
return std::make_shared<ParsingToken<gRegexTokenTypes>>(gRegexTokenTypes::KEY,currentChars);
}
}
mPosition++;
}
//no more to find no one match the currentChars
if (currentChars.empty()) {
return std::make_shared<ParsingToken<gRegexTokenTypes>>(gRegexTokenTypes::STOP,""); // Null shared pointer ;
}else{
throw badTokenError(currentChars,mPosition);
}
}
void GraphLexer::rstPosition(void){
if (isEnd()){
mPosition = 0;
}else{
throw badTokenError("end rst",mPosition);
}
}
bool GraphLexer::isEnd(void){
return mPosition >= mRegularExpressions.length();
}
std::runtime_error GraphLexer::badTokenError(const std::string& currentChars,std::size_t position){
std::ostringstream errorMessage;
errorMessage << "\nBad syntax " << currentChars << " :\n" << mRegularExpressions << "\n";
for (std::size_t i = 0; i < position; i++) {
errorMessage << ' ';
}
errorMessage << "^\n";
return std::runtime_error(errorMessage.str());
}
const std::string GraphLexer::rep(){
std::string out = mRegularExpressions;
out += "\n";
for (std::size_t i = 0; i < mPosition; i++) {
out += ' ';
}
out += "^\n";
return out ;
}
\ No newline at end of file
#include "aidge/graphRegex/GraphParser.hpp"
using namespace Aidge;
GraphParser::GraphParser(const std::string gRegexExpressions):
mLexer(gRegexExpressions)
{
mCurrentToken = mLexer.getNextToken();
}
std::shared_ptr<AstNode<gRegexTokenTypes>> GraphParser::parse(void){
std::shared_ptr<AstNode<gRegexTokenTypes>> astTree = constructAstAllExpr();
rstParser();
return astTree;
}
void GraphParser::rstParser(void){
mLexer.rstPosition();
mCurrentToken = mLexer.getNextToken();
}
void GraphParser::ackToken(gRegexTokenTypes tokenType){
if(mCurrentToken->getType() == tokenType ){
try {
mCurrentToken = mLexer.getNextToken();
} catch (const std::runtime_error& e) {
std::ostringstream errorMessage;
errorMessage << "Graph Lexer error in Parser :\n"<< e.what() << std::endl;
throw std::runtime_error(errorMessage.str());
}
}else{
std::ostringstream errorMessage;
errorMessage << "Bad syntax GraphParser " << static_cast<int>(mCurrentToken->getType()) <<"!="<< static_cast<int>(tokenType) << "\n";
errorMessage << mLexer.rep();
throw std::runtime_error(errorMessage.str());
}
}
/*
exp : KEY(QOM | QZM)? | CKEY | domain
*/
std::shared_ptr<AstNode<gRegexTokenTypes>> GraphParser::constructAstExp(void)
{
try{
std::shared_ptr<ParsingToken<gRegexTokenTypes>> token = mCurrentToken->copy();
std::shared_ptr<AstNode<gRegexTokenTypes>> node = std::make_shared<AstNode<gRegexTokenTypes>>(token);
if (mCurrentToken->getType() == gRegexTokenTypes::KEY ){
ackToken(gRegexTokenTypes::KEY );
if (mCurrentToken->getType() == gRegexTokenTypes::QOM ){
ackToken(gRegexTokenTypes::QOM );
std::shared_ptr<AstNode<gRegexTokenTypes>> newNode = std::make_shared<AstNode<gRegexTokenTypes>>(token,
std::vector<std::shared_ptr<AstNode<gRegexTokenTypes>>>{node});
return newNode;
}else if (mCurrentToken->getType() == gRegexTokenTypes::QZM ){
ackToken(gRegexTokenTypes::QZM );
std::shared_ptr<AstNode<gRegexTokenTypes>> newNode = std::make_shared<AstNode<gRegexTokenTypes>>(token,
std::vector<std::shared_ptr<AstNode<gRegexTokenTypes>>>{node});
return newNode;
}
return node;
}else if (mCurrentToken->getType() == gRegexTokenTypes::CKEY){
ackToken(gRegexTokenTypes::CKEY );
return node;
}else{
return constructAstDomain();
}
} catch (const std::runtime_error& e) {
std::ostringstream errorMessage;
errorMessage << "GraphParser constructAstExp :\n"<< e.what() << std::endl;
throw std::runtime_error(errorMessage.str());
}
}
/*
seq :exp (NEXT seq)*
*/
std::shared_ptr<AstNode<gRegexTokenTypes>> GraphParser::constructAstSeq(void)
{
try{
std::shared_ptr<AstNode<gRegexTokenTypes>> left = constructAstExp();
if(mCurrentToken->getType() == gRegexTokenTypes::NEXT )
{
std::shared_ptr<ParsingToken<gRegexTokenTypes>> token = mCurrentToken->copy();
ackToken(gRegexTokenTypes::NEXT);
std::shared_ptr<AstNode<gRegexTokenTypes>> newNode = std::make_shared<AstNode<gRegexTokenTypes>>(token,
std::vector<std::shared_ptr<AstNode<gRegexTokenTypes>>>{left,constructAstSeq()});
left = newNode;
}
return left;
} catch (const std::runtime_error& e) {
std::ostringstream errorMessage;
errorMessage << "GraphParser constructAstSeq :\n"<< e.what() << std::endl;
throw std::runtime_error(errorMessage.str());
}
}
/*
LPAREN seq RPAREN (QOM | QZM)
*/
std::shared_ptr<AstNode<gRegexTokenTypes>> GraphParser::constructAstDomain(void)
{
try{
std::shared_ptr<ParsingToken<gRegexTokenTypes>> token ;
std::shared_ptr<AstNode<gRegexTokenTypes>> node ;
token = mCurrentToken->copy();
ackToken(gRegexTokenTypes::LPAREN);
node = std::make_shared<AstNode<gRegexTokenTypes>>(token,
std::vector<std::shared_ptr<AstNode<gRegexTokenTypes>>>{constructAstSeq()});
ackToken(gRegexTokenTypes::RPAREN);
//(QOM | QZM)
token = mCurrentToken->copy();
if (mCurrentToken->getType() == gRegexTokenTypes::QOM){
ackToken(gRegexTokenTypes::QOM);
node = std::make_shared<AstNode<gRegexTokenTypes>>(token,
std::vector<std::shared_ptr<AstNode<gRegexTokenTypes>>>{node});
}else if (mCurrentToken->getType() == gRegexTokenTypes::QZM){
ackToken(gRegexTokenTypes::QZM);
node = std::make_shared<AstNode<gRegexTokenTypes>>(token,
std::vector<std::shared_ptr<AstNode<gRegexTokenTypes>>>{node});
}else{
std::ostringstream errorMessage;
errorMessage << "Bad syntax constructAstDomain must have quantifier \n";
throw std::runtime_error(errorMessage.str());
}
return node;
} catch (const std::runtime_error& e) {
std::ostringstream errorMessage;
errorMessage << "GraphParser constructAstDomain :\n"<< e.what() << std::endl;
throw std::runtime_error(errorMessage.str());
}
}
/*
allExpr: seq (SEP allExpr)*
*/
std::shared_ptr<AstNode<gRegexTokenTypes>> GraphParser::constructAstAllExpr(void)
{
try{
std::shared_ptr<AstNode<gRegexTokenTypes>> left = constructAstSeq();
if(mCurrentToken->getType() == gRegexTokenTypes::SEP )
{
std::shared_ptr<ParsingToken<gRegexTokenTypes>> token = mCurrentToken->copy();
ackToken(gRegexTokenTypes::SEP);
std::shared_ptr<AstNode<gRegexTokenTypes>> newNode = std::make_shared<AstNode<gRegexTokenTypes>>(token,
std::vector<std::shared_ptr<AstNode<gRegexTokenTypes>>>{left,constructAstAllExpr()});
left = newNode;
}
return left;
} catch (const std::runtime_error& e) {
std::ostringstream errorMessage;
errorMessage << "GraphParser constructAstDomain :\n"<< e.what() << std::endl;
throw std::runtime_error(errorMessage.str());
}
}
#include "aidge/graphRegex/matchFsm/FsmEdge.hpp"
#include "aidge/graphRegex/matchFsm/FsmNode.hpp"
#include "aidge/graphRegex/matchFsm/FsmRunTimeContext.hpp"
using namespace Aidge;
std::map<std::string,int> FsmEdgeCommon::mCommonIdxMap;
bool FsmEdge::isCommon(void){
return false;
}
size_t FsmEdge::getCommonIdx(void){
return std::numeric_limits<std::size_t>::max();
}
const std::map<size_t,int>& FsmEdge::getRelative(void){
return mRelativePos;
}
void FsmEdge::updateRelative( const std::map<size_t,int>& relativePos ){
for (const auto& kvp : relativePos) {
mRelativePos.insert(kvp);
}
}
std::shared_ptr<FsmNode> FsmEdge::getSourceNode(void){
return mNodeSource;
}
void FsmEdge::reSetSouceNode(const std::shared_ptr<FsmNode>& newSource){
mNodeSource->rmEdge(shared_from_this());
mNodeSource = newSource;
mNodeSource->addEdge(shared_from_this());
propagateRelativePos();
}
std::shared_ptr<FsmNode> FsmEdge::getDestNode(void){
return mNodeDest;
}
void FsmEdge::reSetDestNode(const std::shared_ptr<FsmNode>& newDest){
mNodeDest->rmParent(mNodeSource);
mNodeDest = newDest;
mNodeDest->addParent(mNodeSource);
propagateRelativePos();
}
void FsmEdge::propagateRelativePos(void){
std::set<int> myRelativeID;
for (const auto& kvp : mRelativePos) {
myRelativeID.insert(kvp.first);
}
for (const auto nextWeakEdge : mNodeDest->getEdges()){
if (auto nextEdge = nextWeakEdge.lock()) {
if(this == nextEdge.get()){
continue;
}
std::set<int> nextRelativeID;
for (const auto& kvp : nextEdge->getRelative()) {
nextRelativeID.insert(kvp.first);
}
// Find elements in myRelativeID but not in nextRelativeID
std::set<int> idxsToPush;
std::set_difference(myRelativeID.begin(), myRelativeID.end(),
nextRelativeID.begin(), nextRelativeID.end(),
std::inserter(idxsToPush, idxsToPush.begin()));
// Find elements in nextRelativeID but not in myRelativeID
std::set<int> idxsToGet;
std::set_difference(nextRelativeID.begin(), nextRelativeID.end(),
myRelativeID.begin(), myRelativeID.end(),
std::inserter(idxsToGet, idxsToGet.begin()));
// test for integrity we look if 2 edge refert to the samme
// ref and are link the ref dif is one
// not working for common node
// we can go deeper by find the all pass to a ref and see if the delta is good
// Find elements present in both myRelativeID and nextRelativeID
std::set<int> idxsTotest;
for (int idx : nextRelativeID){
if (myRelativeID.find(idx) != myRelativeID.end()){
if (std::abs(getRelative().at(idx) - nextEdge->getRelative().at(idx)) != 1) {
throw std::runtime_error("Bad relative");
}
}
}
// this egde have more relative info than the next
std::map<size_t,int> tmpRelative;
// we push this info to the next
for( auto idxToPush :idxsToPush ){
tmpRelative.insert( std::make_pair(idxToPush, getRelative().at(idxToPush) +1));
}
if(tmpRelative.size() != 0){
nextEdge->updateRelative(tmpRelative);
nextEdge->propagateRelativePos();
}
tmpRelative.clear();
// the next node have more info than me i need to get it
for( auto idxToGet :idxsToGet ){
tmpRelative.insert( std::make_pair(idxToGet, nextEdge->getRelative().at(idxToGet) -1));
}
if(tmpRelative.size() != 0){
updateRelative(tmpRelative);
for(auto weakParent : getSourceNode()->getParentNodes()){
if (auto parent = weakParent.lock()) {
for(auto weakPEdge : parent->getEdges()){
if (auto pEdge = weakPEdge.lock()) {
pEdge->propagateRelativePos();
}else{
throw std::runtime_error("propagateRelativePos parent edge weak pointer is expired" );
}
}
}else{
throw std::runtime_error("propagateRelativePos parent weak pointer is expired" );
}
}
}
tmpRelative.clear();
}else{
throw std::runtime_error("propagateRelativePos edge weak pointer is expired" );
}
}
}
FsmEdge::FsmEdge(std::shared_ptr<FsmNode> source,std::shared_ptr<FsmNode> dest, const std::shared_ptr<ConditionalInterpreter> toTest)
:mToTest(toTest)
{
mNodeSource = source;
mNodeDest = dest;
}
/////surchage
FsmEdgeUnique::FsmEdgeUnique(std::shared_ptr<FsmNode> source,std::shared_ptr<FsmNode> dest, const std::shared_ptr<ConditionalInterpreter> toTest)
:FsmEdge(source,dest,toTest)
{
}
const EdgeTestResult FsmEdgeUnique::test(const std::shared_ptr<FsmRunTimeContext> stmContext){
if(stmContext == nullptr){
return {false,std::set<NodePtr>()};//none
}
auto opNode = stmContext->getActNode();
if(mToTest->test(opNode) && opNode->getChildren().size() <= 1){
stmContext->setValid(opNode,mToTest);
return {true,opNode->getChildren()} ;
}else{
stmContext->addRejectedNode(opNode);
return {false,std::set<NodePtr>()};
}
}
/////////////////////
FsmEdgeCommon::FsmEdgeCommon(std::shared_ptr<FsmNode> source,std::shared_ptr<FsmNode> dest, const std::shared_ptr<ConditionalInterpreter> toTest, const std::string commonKey)
:FsmEdge(source,dest,toTest)
{
//make a uid for common node
if(mCommonIdxMap.find(commonKey) == mCommonIdxMap.end()){
mCommonIdxMap.insert(std::make_pair(commonKey, mCommonIdxMap.size()));
}
mCommonIdx = mCommonIdxMap[commonKey];
propagateRelativePos();
}
const EdgeTestResult FsmEdgeCommon::test(const std::shared_ptr<FsmRunTimeContext> stmContext){
if(stmContext == nullptr){
return {false,std::set<NodePtr>()};//none
}
auto opNode = stmContext->getActNode();
if(mToTest->test(opNode)){
stmContext->setCommon(opNode,mCommonIdx);
stmContext->setValid(opNode,mToTest);
return {true,opNode->getChildren()} ;
}else{
stmContext->addRejectedNode(opNode);
return {false,std::set<NodePtr>()};
}
}
bool FsmEdgeCommon::isCommon(void){
return true;
}
//////////////////// TODO FsmEdgeEmpty must be size_t
FsmEdgeRef::FsmEdgeRef(std::shared_ptr<FsmNode> source,std::shared_ptr<FsmNode> dest, const size_t refCommonIdx,const int deltaCommonIdx)
:FsmEdge(source,dest,nullptr),mRefCommonIdx(refCommonIdx),mdeltaCommonIdx(deltaCommonIdx)
{
}
const EdgeTestResult FsmEdgeRef::test(const std::shared_ptr<FsmRunTimeContext> stmContext){
NodePtr refNode = stmContext->getCommonNodeFromIdx(mRefCommonIdx);
if (refNode){
//return {true,refNode->getNodeDelta(mdeltaCommonIdx)}; TODO
}
return {false,std::set<NodePtr>()};
}
////////////////////
FsmEdgeEmpty::FsmEdgeEmpty(std::shared_ptr<FsmNode> source,std::shared_ptr<FsmNode> dest)
:FsmEdge(source,dest,nullptr)
{}
const EdgeTestResult FsmEdgeEmpty::test(const std::shared_ptr<FsmRunTimeContext> stmContext){
if(stmContext == nullptr){
return {false,std::set<NodePtr>()};
}
auto opNode = stmContext->getActNode();
return {true,std::set<NodePtr>({opNode})};//none
}
/// factory
std::shared_ptr<FsmEdge> FsmEdgeFactory::make(
std::shared_ptr<FsmNode> source,
std::shared_ptr<FsmNode> dest, FsmEdgeTypes type,
std::map<std::string, std::shared_ptr<ConditionalInterpreter>> allTest,
const std::string lexeme)
{
if (type == FsmEdgeTypes::EMPTY) {
if (lexeme.empty()) {
return std::make_shared<FsmEdgeEmpty>(source, dest);
} else {
throw std::invalid_argument("error lexem EMPTY");
}
} else if (type == FsmEdgeTypes::REF) {
std::smatch m;
std::regex refRegex("\\s*\\(\\s*(\\d+)\\s*,\\s*(-?\\d+)\\s*\\)\\s*");
if (std::regex_match(lexeme, m, refRegex)) {
int refCommonIdx = std::stoi(m[1]);
int deltaCommonIdx = std::stoi(m[2]);
return std::make_shared<FsmEdgeRef>(source, dest, refCommonIdx, deltaCommonIdx);
} else {
throw std::invalid_argument("error lexem REF " + lexeme);
}
} else if (type == FsmEdgeTypes::COMMON) {
std::smatch m;
std::regex commonRegex("\\s*(\\w+)#(\\d*)");
if (std::regex_match(lexeme, m, commonRegex)) {
std::string edgeType = m[1];
std::string commonId = m[2];
size_t commonIdx = commonId.empty() ? 0 : std::stoi(commonId) + 1;
std::string commonKey = edgeType + std::to_string(commonIdx);
return std::make_shared<FsmEdgeCommon> (source, dest, allTest.at(edgeType), commonKey);
} else {
throw std::invalid_argument("error lexem COMMON " + lexeme);
}
} else if (type == FsmEdgeTypes::UNIQUE) {
std::regex uniqueRegex("\\s*(\\w+)");
std::smatch m;
if (std::regex_match(lexeme, m, uniqueRegex)) {
std::string edgeType = m[1];
return std::make_shared<FsmEdgeUnique>(source, dest, allTest.at(edgeType));
} else {
throw std::invalid_argument("error lexem UNIQUE \"" + std::string(lexeme) +" eee\"");
}
} else {
throw std::invalid_argument("Bad edge Type");
}
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment