- // re-start the process
- do_gdelete();
- }
- else if (gfuther.isC())
- {
- // the grand futher is a control element: since the parent is a phantom group,
- // the TML tree should be in a inconsistent state (once removed the parent).
-
- // being here means that there is a frame in the stack
- assert(!frames.empty());
- cout << "do_gdelete: i have to remove a phantom group whuch is a child of a MACRO" << endl;
- Frame& frame = frames.top();
- if (frame.entry.leftOpen && frame.entry.rightOpen)
- {
- // in this case, the cursor is in the second and last child
- // of the MACRO. We can assert that the grand futher has two
- // children. which are both phantom group
- cout << "do_gdelete: the MACRO is leftOpen and rigthOpen" << endl;
- assert(gfuther.size() == 2);
- assert((gfuther.last() == parent) && (gfuther.first().isG() && !gfuther.first().hasId()));
- assert(frame.pos == 0);
-
- TNode ggfuther = gfuther.parent();
- assert(ggfuther);
- cursor.remove();
- parent.remove();
- // i have to replace the gfuther with the elements of its first child
- gfuther.replace(gfuther.first().first(), TNode());
- cout << "do_gdelete: i have removed the control element, and replaced it with its first child" << endl;
- ggfuther.append(cursor);
- cout << "do_gdelete: cursor appended to the grand grand futher" << endl;
-
- // now we have the situation preceding the insertion of the MACRO leftOpen and rightOpen
- // this MACRO no longer exists.
- frames.pop();
- }
- else if (frame.entry.rightOpen)
- {
- // the user has inserted a MACRO rightOpen. Since the cursor is the
- // only child of the MACRO, the user want to remove it.
- // We can assert that cursor's parent is the only child of the MACRO
- cout << "do_gdelete: the MACRO is rightOpen only" << endl;
- assert(gfuther.size() == 1);
- assert(frame.pos == 0); // i think this assert has no sense
-
- cursor.remove();
- parent.remove();
- gfuther.replace(cursor);
-
- // now we have the situation preceding the MACRO rightOpen, so i have to pop the frame
- frames.pop();
- }
- else if (frame.entry.leftOpen)
- {
- // it' s an unpredicted situation
- cout << "it's a bad situation, maybe handlable, but unpredicted" << endl;
- }
- else if (!frame.entry.pattern.empty())
- {
- // the MACRO (the cursor's grand futher) accepts arguments.
- // we have to control if the cursor's uncle does exist.
-
- if (parent.prev())
- {
- // in this case, we can assert that frame in the stack has
- // pos greater than 0
- assert(frame.pos > 0);
-
- // cursor's uncle does exist. we have to control
- // its nature (is it a phantom group?)
- TNode uncle = parent.prev();
- if (uncle.isG() && !uncle.hasId())
- {
- // the cursor's parent is a phantom group, so it was a
- // delimited argument of the MACRO and the corrisponding
- // delimeter is inserted. So, the action of deleting means
- // removing this delimeter
- cursor.remove();
- parent.remove();
- uncle.append(cursor);
- frame.pos -= 2;
- }
- else
- {
- // the uncle was a NOT delimited argument. So i try to
- // remove it
- cursor.remove();
- parent.replace(cursor);
-
- parent = cursor.parent(); // i update the parent (it should be the MACRO)
- assert(parent.isC());
-
- gdelete_prev();
-
- }
- }
- else
- {
- // cursor's parent is the only child of the MACRO, which accepts arguments
- // i can assert that frame.pos == 0.
- // In this case i can replace the MACRO with the cursor
- assert(frame.pos == 0);
-
- cursor.remove();
- parent.remove();
- gfuther.replace(cursor);
-
- frames.pop();
- }
-
- }
- }
- }
- else // the grand futher is math
- {
- // nothing to do...i think
- assert(frames.empty());
+}
+
+std::string
+TPushParser::do_drop_groupId(bool special)
+{
+ // if we are here, the cursor's parent is a group with Id
+ assert(cursor.parent() && cursor.parent().isG() && cursor.parent().hasId());
+ TNode parent = cursor.parent();
+
+ // we have to take different actions based on if the cursor has a preceding
+ // element or not
+ TNode prev = cursor.prev();
+ if (prev)
+ {
+ // the cursor has a preceding element, so we try to remove it
+ if (special) return drop_prev(special);
+ else
+ {
+ std::string str = drop_prev(special);
+
+ // We control if the group has to be removed, because the cursor
+ // might be the only element of the group.
+ // But we have to be careful, because drop_prev could change the TML tree
+ // more than we think...parent could no longer exist!
+ parent = cursor.parent();
+ if ((parent.first() == cursor) && parent.isG() && parent.hasId())
+ rgreplace_father();
+
+ return str;
+ }
+ }
+ else
+ {
+ // the cursor has no preceding elements, so we have to remove the
+ // group.
+ if (special)
+ {
+ parent.replace(cursor);
+ return "";
+ }
+ else
+ {
+ rgreplace_father();
+ // we have to re-start the process, because it' a graphical deletion
+ return do_drop(special);
+ }
+ }
+
+} // end of method do_drop_groupId()
+
+std::string
+TPushParser::do_drop_phantom_group(bool special)
+{
+ // if we are here, the cursor MUST be a child of a
+ // phantom group.
+ assert(cursor.parent() && cursor.parent().isG() && !cursor.parent().hasId());
+
+ TNode parent = cursor.parent();
+
+ // now we have to control if the cursor has a preceding element or not
+ TNode prev = cursor.prev();
+ if (prev)
+ {
+ if (parent.parent() && parent.parent().isC())
+ {
+ // there is a frame in the stack
+ assert(!frames.empty());
+ if (frames.top().entry.pattern.size())
+ {
+ Frame& frame = frames.top();
+ if (special)
+ {
+ // we are in a delimited argument. If the user has inserted a proper subset of the
+ // delimiters'sequence, we start to remove the previous delimiter. Start to remove
+ // a delimiter means that that delimiter must be removed from the count of inserted delimiters.
+ // It means that we have to decrement the member pos.
+ if (frame.entry.pattern[frame.pos].category != TToken::PARAMETER)
+ {
+ std::string del = frame.entry.pattern[frame.pos].value;
+ frame.pos--;
+ return "\\" + del;