File indexing completed on 2024-05-12 04:37:46

0001 /*
0002     SPDX-FileCopyrightText: 2008 Hamish Rodda <rodda@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-only
0005 */
0006 
0007 #ifndef KDEVPLATFORM_ASTCHANGESET_H
0008 #define KDEVPLATFORM_ASTCHANGESET_H
0009 
0010 #include <QVariant>
0011 
0012 namespace KDevelop {
0013 template <typename AstNode>
0014 class AstChangeSet;
0015 
0016 class AstChange;
0017 
0018 /**
0019  * \short A reference to an existing read-only AST node.
0020  *
0021  * This class represents an AST node, and allows changes to be planned
0022  * for that node.
0023  *
0024  * \warning you must not create cyclic references.
0025  *
0026  * \author Hamish Rodda <rodda@kde.org>
0027  */
0028 template <typename AstNode>
0029 class AstNodeRef
0030 {
0031     friend class AstChangeSet<AstNode>;
0032 
0033 public:
0034     /// Destructor.
0035     virtual ~AstNodeRef()
0036     {
0037         qDeleteAll(m_changes);
0038 
0039         if (m_newNode)
0040             delete m_node;
0041     }
0042 
0043     using AstNodeList = QList<AstNodeRef*>;
0044 
0045     /**
0046      * \short Container class for a change to an AST node.
0047      *
0048      * \author Hamish Rodda <rodda@kde.org>
0049      */
0050     class AstChange
0051     {
0052 public:
0053         enum ChangeTypes {
0054             ListRewrite,
0055             ListClear,
0056             ItemReplace,
0057             ItemMove
0058         };
0059 
0060         explicit AstChange(ChangeTypes t)
0061             : type(t)
0062             , newNode(0)
0063             , listOffset(-1)
0064             , newValue(-1)
0065         {
0066         }
0067 
0068         ChangeTypes type;
0069         // The index of the item in the node to be changed
0070         int nodeIndex;
0071 
0072         // The new node to occupy this position, if relevant
0073         AstNodeRef* newNode;
0074         // The list of nodes to occupy this position, if relevant
0075         AstNodeList newList;
0076         // The position to apply the node(s) in the list, if relevant
0077         int listOffset;
0078         // The value of the position, if relevant
0079         QVariant newValue;
0080     };
0081 
0082     virtual const AstNode* node() const
0083     {
0084         return m_newNode ? 0 : m_node;
0085     }
0086 
0087     virtual AstNodeRef* nodeRef() const
0088     {
0089         return m_nodeRef;
0090     }
0091 
0092     virtual AstNode* newNode() const
0093     {
0094         return m_newNode ? m_node : 0;
0095     }
0096 
0097     const QList<AstChange*>& changes() const
0098     {
0099         return m_changes;
0100     }
0101 
0102     /// Adds a change to this node reference. Takes ownership of the \a change.
0103     AstChange* newChange(AstChange* change)
0104     {
0105         m_changes.append(change);
0106         return change;
0107     }
0108 
0109     /// Removes a change from this node reference, and deletes it.
0110     void deleteChange(AstChange* change)
0111     {
0112         Q_ASSERT(m_changes.contains(change));
0113         m_changes.removeAll(change);
0114         delete change;
0115     }
0116 
0117 protected:
0118     /// Default constructor. \todo is this needed?
0119     AstNodeRef(AstChangeSet<AstNode>* set)
0120         : m_changeSet(set)
0121         , m_node(0)
0122         , m_nodeRef(0)
0123         , m_newNode(false)
0124     {
0125     }
0126 
0127     /// Constructor.  Either takes an existing \a node (\a newNode = false), or a newly created \a node (\a newNode = true)
0128     AstNodeRef(AstChangeSet<AstNode>* set, AstNode* node, bool newNode)
0129         : m_changeSet(set)
0130         , m_node(node)
0131         , m_nodeRef(0)
0132         , m_newNode(newNode)
0133     {
0134     }
0135 
0136     /// Constructor.  Takes another node reference.
0137     AstNodeRef(AstChangeSet<AstNode>* set, AstNodeRef* original)
0138         : m_changeSet(set)
0139         , m_node(0)
0140         , m_nodeRef(original)
0141         , m_newNode(false)
0142     {
0143     }
0144 
0145     AstNode* m_nodeChanges;
0146 
0147 private:
0148     AstChangeSet<AstNode>* m_changeSet;
0149     AstNode* m_node;
0150     AstNodeRef* m_nodeRef;
0151     bool m_newNode;
0152 
0153     QList<AstChange*> m_changes;
0154 };
0155 
0156 /**
0157  * \short A set of changes to an AST.
0158  *
0159  * This class holds a set of all changes to an AST.
0160  *
0161  * \author Hamish Rodda <rodda@kde.org>
0162  */
0163 template <typename AstNode>
0164 class AstChangeSet
0165 {
0166 public:
0167     /**
0168      * Constructor.
0169      *
0170      * \param topNode the top node of the read-only Ast to modify, or set to null if creating
0171      *                a new Ast from scratch.
0172      */
0173     AstChangeSet(const AstNode* topNode = 0)
0174         : m_topNode(topNode)
0175     {
0176     }
0177 
0178     /**
0179      * Destructor, deletes all nodes owned by this change set.
0180      */
0181     virtual ~AstChangeSet()
0182     {
0183         qDeleteAll(m_nodeRefs);
0184     }
0185 
0186     /**
0187      * Register a new node that you have created to insert at some point in this Ast.
0188      * You may modify this node directly.  The change set takes ownership, so that
0189      * the new node will be deleted when the change set is no longer needed.
0190      *
0191      * \returns the new node that has been registered.
0192      */
0193     AstNodeRef<AstNode>* registerNewNode(AstNode* node)
0194     {
0195         AstNodeRef<AstNode>* newRef = new AstNodeRef<AstNode>(this, node, true);
0196         m_nodeRefs.append(newRef);
0197         return newRef;
0198     }
0199 
0200     /**
0201      * Create a blank reference to a node.
0202      *
0203      * The change set takes ownership, so that
0204      * the new node will be deleted when the change set is no longer needed.
0205      *
0206      * \returns the new node reference
0207      */
0208     AstNodeRef<AstNode>* registerNewRef(AstNodeRef<AstNode>* ref)
0209     {
0210         m_nodeRefs.append(ref);
0211         return ref;
0212     }
0213 
0214     /**
0215      * Copy an existing node (whether from the Ast or from the change set).
0216      *
0217      * You may then modify this reference, and the modifications will be applied to the node when the change set is finalised.
0218      *
0219      * \returns a copy of \a source, which you may modify directly.
0220      */
0221     AstNodeRef<AstNode>* copyNode(AstNode* source)
0222     {
0223         AstNodeRef<AstNode>* newRef = new AstNodeRef<AstNode>(this, source, false);
0224         m_nodeRefs.append(newRef);
0225         return newRef;
0226     }
0227 
0228 private:
0229     const AstNode* m_topNode;
0230     QList<AstNodeRef<AstNode>*> m_nodeRefs;
0231 };
0232 }
0233 
0234 #endif // KDEVPLATFORM_ASTCHANGESET_H