cursor["id"] = "I0";
doc.clearDirty();
doc.root().append(cursor);
+ logger.verbosity(ALogger::Debug);
}
TPushParser::~TPushParser()
assert(row && row.is("row"));
TNode table = row.parent();
assert(table);
- advance(table);
-
- // now we have to pop the associated frame in the stack
- frames.pop();
+ advance(row);
}
else if (parent && parent.isG() && !parent.hasId() && parent.parent())
{
// closing brace for a right-open macro (like \over)
+ // It's not sure that we want to exit from a phantom group with a
+ // '}', because, to enter in the phantom group the user didn't insert a
+ // '{'.
cursor.remove();
- advance(parent.parent());
- frames.pop();
+ advance(parent);
}
else
{
- // ???
- assert(0);
+ // In this case, there is a redundant '}', so I think we can ignore it and
+ // emit an error
+ logger.error("There so no corresponding'{'");
+ //assert(0);
}
}
else
{
// we need two closing math shifts
+ //cursor.remove(); ??
parent.parent().append(cursor);
}
}
}
else
{
- cerr << "ERROR: math shift" << endl;
+ // In TeX, the user can type
+ // $a-b\over2a+b$
+ // In this case, '$' character is correct.
+ // I don't think so, if user types
+ // $12+{a-b\over2a+b$
+ // because the group is not closed with a '}'
+ logger.error("ERROR: math shift");
}
}
}
else
{
- cerr << "alignment tab used outside matrix" << endl;
+ logger.error("alignment tab used outside matrix");
}
}
}
else if (parent.isSb() && cursor == parent[1])
{
- if (parent["under"] == "1") cerr << "already under" << endl;
+ if (parent["under"] == "1") logger.error("already under");
else parent["under"] = "1";
}
}
}
else if (parent.isSp() && cursor == parent[1])
{
- if (parent["over"] == "1") cerr << "already over" << endl;
+ if (parent["over"] == "1") logger.error("already over");
else parent["over"] = "1";
}
}
}
else
{
- // error ???
+ // is it an error?
+ logger.error("you have to type one identifier before the ''");
}
}
else
TNode m = doc.createC(name, nextId++);
cursor.replace(m);
- cout << "ecco tutti i token del pattern della entry inserita" << endl;
+ logger.debug("do_control: i have pushed a frame in the stack. Here is the pattern of the associated MACRO");
for (unsigned i = 0; i < entry.pattern.size(); i++)
- cout << entry.pattern[i].value << endl;
+ logger.debug(entry.pattern[i].value);
if (entry.leftOpen && entry.rightOpen)
{
{
frames.push(Frame(entry));
- if (entry.table)
- cout << "do_control: we have a table" << endl;
-
if (entry.paramDelimited(0))
{
- cout << "do_control: it'a MACRO with delimited first argument" << endl;
TNode g = doc.createG();
m.append(g);
g.append(cursor);
else
{
// error, but we could handle this very easily
- cerr << "error, but we could handle this easily" << endl;
+ logger.error("error, but we could handle this easily");
}
}
else advance(m);
break;
case TDictionary::UNDEFINED:
{
- cerr << "ERROR: using undefined macro `" << name << "'" << endl;
+ logger.error("ERROR: using undefined macro ` + name '");
TNode m = doc.createC(name, nextId++);
cursor.replace(m);
advance(m);
}
void
-TPushParser::gdelete_prev()
+TPushParser::gdelete_prev_token()
{
- // if in this function, the prev of cursor does exist, also the parent and we want a graphical deleting.
-
assert(cursor.prev());
assert(cursor.parent());
-
TNode prev = cursor.prev();
- if (prev.is("i") || prev.is("o") || prev.is("n"))
+ assert(prev.is("i") || prev.is("o") || prev.is("n"));
+
+ logger.debug("gdelete_prev_token: start");
+
+ // the control below is designed to handle the case in which val have more than one unicode character
+ DOM::UCS4String ucs4val(prev.element().getAttribute("val"));
+ if ((ucs4val.length() <= 1) || prev.element().hasAttribute("name"))
{
- // the control below is designed to handle the case in which val have more than one unicode character
- DOM::UCS4String ucs4val(prev.element().getAttribute("val"));
- if ((ucs4val.length() <= 1) || prev.element().hasAttribute("name"))
+ logger.debug("gdelete_prev_token: i have removed an element");
+ cursor.remove();
+ prev.replace(cursor);
+
+ if (cursor.parent().isC())
{
- cursor.remove();
- prev.replace(cursor);
-
- if (cursor.parent().isC())
- {
- // in this case we have removed an element of a MACRO.
- // we can assert that this element was a non delimited argument
- assert(!frames.empty());
- Frame& frame = frames.top();
- assert(frame.pos > 0);
+ // in this case we have removed an element of a MACRO.
+ // we can assert that this element was a non delimited argument
+ assert(!frames.empty());
+ Frame& frame = frames.top();
+ assert(frame.pos > 0);
- frame.pos--;
- }
- }
- else
- {
- ucs4val.erase(ucs4val.length() - 1, 1);
- prev.element().setAttribute(DOM::GdomeString("val"), DOM::GdomeString(ucs4val));
+ frame.pos--;
+ logger.debug("gdelete_prev_token: it was a MACRO's child so i have decremented the member pos of the associated frame");
}
- } // end of if (prev.is("i") || ...)
- else if (prev.is("sp") || prev.is("sb"))
+ }
+ else
{
- cursor.remove();
- prev.append(cursor);
- gdelete_prev();
- } // end of if (prev.is("sp") || prev.is("sb"))
- else if (prev.isG())
+ ucs4val.erase(ucs4val.length() - 1, 1);
+ prev.element().setAttribute(DOM::GdomeString("val"), DOM::GdomeString(ucs4val));
+ }
+
+ logger.debug("gdelete_prev_token: bye...");
+}
+
+void
+TPushParser::gdelete_prev_script()
+{
+ logger.debug("gdelete_prev_script: start...");
+ // this method delete a sp or an sb preceding the cursor
+ assert(cursor.prev());
+ assert(cursor.parent());
+ TNode prev = cursor.prev();
+ assert(prev.is("sp") || prev.is("sb"));
+ cursor.remove();
+ prev.append(cursor);
+ // i can invoke the gdelet_prev, because a sp (sb) MUST have two child
+ gdelete_prev();
+ logger.debug("gdelete_prev_script: bye...");
+}
+
+void
+TPushParser::gdelete_prev_group()
+{
+ logger.debug("gdelete_prev_group: start");
+ assert(cursor.prev() && cursor.prev().isG());
+ TNode prev = cursor.prev();
+ cursor.remove();
+ prev.append(cursor);
+ logger.debug("gdelete_prev_group: i have to call the do_gdelete()");
+
+ // a group can have no child, so the gdelete_prev is not appropriate
+ // so this method is not equivalent to the one above
+ do_gdelete();
+
+ logger.debug("gdelete_prev_group: do_gdelete terminated");
+ logger.debug("gdelete_prev_group: bye...");
+}
+
+void
+TPushParser::gdelete_prev_macro()
+{
+ logger.debug("gdelete_prev_macro: start");
+ assert(cursor.parent());
+ assert(cursor.prev());
+ TNode prev = cursor.prev();
+ assert(prev.isC());
+
+ const TDictionary::Entry& entry = dictionary.find(prev["name"]);
+
+ if (!entry.defined())
{
+ // I assume tha the user want to completely delete the undefined macro
+ logger.debug("gdelete_prev_macro: i have to remove an undefined macro");
cursor.remove();
- prev.append(cursor);
- do_gdelete();
+ prev.replace(cursor);
}
- else if (prev.isC() && dictionary.find(prev["name"]).cls != TDictionary::UNDEFINED)
+ else
{
- const TDictionary::Entry& entry = dictionary.find(prev["name"]);
-
- // i start to remove a MACRO. The frame associated to this MACRO was
- // popped from the stack (i think). So, i re-push the frame in the stack,
- // but the pos member should be set correctly
- cout << "gdelete_prev: i have to start to delete a MACRO" << endl;
+ logger.debug("gdelete_prev_macro: i have to start to delete a defined MACRO");
+
+ // i start to remove a MACRO. Different actions must be taken, based on the nature
+ // of the MACRO. In some case, we can't remove the MACRO immediately, in other
+ // case it's correct. In the first case, we have to update the stack, pushing
+ // a frame in the stack with a correct value of pos, in the
+ // second one, we do not have to push a frame in the stack
- // if the control element is leftOpen and rightOpen, the cursor should be placed after
- // the last child of the control element's last child
if (entry.rightOpen)
{
- cout << "gdelte_prev(): i have to delete a control rightOpen, so i push an element in the stack" << endl;
- Frame frame(entry);
- frames.push(frame);
+ // if the control element is ightOpen, the cursor should be placed after
+ // the last child of the control element's last child, and try to remove something
+ // A frame MUST be pushed in the stack, because we dont' know if the following actions
+ // will remove the MACRO.
+ logger.debug("gdelte_prev_macro: i have to delete a control rightOpen, so i push an element in the stack");
+
+ frames.push(Frame(entry));
+
+ logger.debug("gdelete_prev_macro: i control the values of the pushed frame");
+ logger.debug("gdelete_prev_macro: rightOpen");
+ cout << frames.top().entry.rightOpen << endl;
+ logger.debug("gdelete_prev_macro: leftOpen");
+ cout << frames.top().entry.leftOpen << endl;
+ logger.debug("gdelete_prev_macro: pattern.empty()");
+ cout << frames.top().entry.pattern.empty() << endl;
+
+ // Since the MACRO is rightOpen, the last child of the MACRO must be a phantom group
+ assert(prev.last().isG() && !prev.last().hasId());
cursor.remove();
prev.last().append(cursor);
- do_gdelete();
+
+ // the gdelete_prev is not appropriate, because the last child of the MACRO could have no child
+ logger.debug("gdelete_prev_macro: i have to call do_gdelete_phantom_group");
+ do_gdelete_phantom_group();
+
+ if (!frames.empty())
+ {
+ logger.debug("gdelete_prev_macro: after the do_gdelete_phantom_group, the frame in the stack has to be rightOpen");
+ cout << frames.top().entry.rightOpen << endl;
+ logger.debug("gdelte_prev_macro: after the do_gdelete_phantom_group, the top element's pattern MUST be empty");
+ cout << frames.top().entry.pattern.empty() << endl;
+ }
+ else
+ logger.debug("gdelete_prev_macro: the do_gdelete_phantom_group has removed all frames in the stack");
+
}
else if (entry.leftOpen)
{
- cout << "gdelete_prev: i have to delete a control element with leftOpen" << endl;
+ logger.debug("gdelete_prev_macro: i have to delete a control element with leftOpen");
+ // the leftOpen MACRO MUST have one and only one child, which MUST be a phantom group
+ // In this case, we do not have to push a frame in the stack, because we remove the
+ // MACRO immediately, substituting it with the content of the phantom group.
+ // At the moment, i don't remove the last child of the phantom group, but
+ // i don't know if it's the correct behavior of the graphical deleting.
+ // To delete it, just remove the comment of the last instruction
assert(prev.first());
assert(prev.first().isG());
assert(prev.first() == prev.last());
+
TNode g = prev.first();
g.remove();
prev.replace(g.first(), TNode());
+ //do_gdelete();
}
else if (!entry.pattern.empty())
- {
+ {
// we have to start removing a MACRO which accepts arguments.
// a MACRO without child does not exist
- cout << "gdelete_prev: i have to remove a MACRO with argument" << endl;
-
+ logger.debug("gdelete_prev_macro: i have to remove a MACRO with argument");
assert(prev.size() >= 1);
+ // Differnt actions should be taken, based on the nature of the last child
+ // of the MACRO. We have to distinguish the case in which it's a delimited argument
+ // frome the one in which it's a not delimited argument.
if (prev.last().isG() && !prev.last().hasId())
{
- // this means that the last child of the MACRO is a phantom group,
- // which in turn means that it is a delimited argument
- // so we have to ideally remove this delimiter
+ // the last argument of the MACRO is a delimited argumet. We ideally remove
+ // the sequence of delimiters
+ logger.debug("gdelete_prev_macro: the last argument of the MACRO is delimited");
cursor.remove();
prev.last().append(cursor);
// i have to push a frame with a correct value of pos
- Frame frame(entry);
assert(entry.previousParam(entry.pattern.size()) != entry.pattern.size());
unsigned sequence_length = entry.pattern.size() - entry.previousParam(entry.pattern.size()) - 1;
- frame.pos = entry.pattern.size() - sequence_length - 1;
- frames.push(frame);
- cout << "gdelete_prev: i have inserted a frame, it's pos is: " << frames.top().pos << endl;
+ unsigned p = entry.pattern.size() - sequence_length - 1;
+ frames.push(Frame(entry, p));
+ logger.debug("gdelete_prev_macro: i have inserted a frame, it's pos is: ");
+ cout << frames.top().pos << endl;
+
}
else
{
- // in this case, the last child of the MACRO is
- // an argument which is NOT delimited, so i try to
- // remove it
- cout << "gdelete_prev: i try to remove the last argumet of the MACRO" << endl;
+ // in this case, the last child of the MACRO is not a delimited argument, so we try
+ // to remove it, but we have to take differnt actions if the MACRO is a table with rows or not.
+ logger.debug("gdelete_prev_macro: the last argumet of the MACRO is not delimited, so itry to remove it");
cursor.remove();
if (entry.table == 1 && prev.last().is("row"))
{
- // in this case should be appended to the group associated to
+ // in this case the cursor should be appended to the group associated to
// the last cell of the last row of the table
+ logger.debug("gdelete_prev_macro: but it is a table with rows, so i append the cursor at the end of the table");
assert(prev.last().last().is("cell") && prev.last().last().first().isG());
prev.last().last().first().append(cursor);
}
- else prev.append(cursor);
+ else
+ {
+ logger.debug("gdelete_prev_macro: i append the cursor to the MACRO");
+ prev.append(cursor);
+ }
+
+ frames.push(Frame(entry, entry.pattern.size()));
- Frame frame(entry);
- frame.pos = entry.pattern.size();
- frames.push(frame);
+ logger.debug("gdelete_prev_macro: i've pushed a frame in the stack, and it's value of pos is ");
+ cout << frames.top().pos << endl;
- if (cursor.prev()) gdelete_prev();
- else do_gdelete();
+ if (cursor.prev())
+ {
+ logger.debug("gdelete_prev_macro: i invoke the gdelete_prev");
+ gdelete_prev();
+ }
+ else
+ {
+ logger.debug("gdelete_prev_macro: i invoke the do_gdelete");
+ do_gdelete();
+ }
+ } // end of the else of the if (prev.last().isG() && !prev.last().hasId())
- }
+ } // end of if (!entry.pattern.empty())
+ else
+ {
+ // if we are here, the MACRO preceding the cursor, is not rightOpen, nor leftOpen,
+ // and has no pattern. It means that it has no childs.
+ // We can replace it with the cursor
+ logger.debug("gdelete_prev_macro: the MACRO is empty, i remove it");
+ assert(prev.size() == 0);
+ cursor.remove();
+ prev.replace(cursor);
}
+ } // end of defined MACRO
+
+ logger.debug("gdelete_prev_macro: bye...");
+}
+
+void
+TPushParser::gdelete_prev()
+{
+ // if in this function, the prev of cursor does exist, also the parent and we want a graphical deleting.
+
+ logger.debug("gdelete_prev: start...");
+
+ assert(cursor.prev());
+ assert(cursor.parent());
+
+ TNode prev = cursor.prev();
+
+ if (prev.is("i") || prev.is("o") || prev.is("n"))
+ {
+ gdelete_prev_token();
}
- else if (dictionary.find(prev["name"]).cls == TDictionary::UNDEFINED)
+ else if (prev.isSp() || prev.isSb())
{
- // The user wants to delete an undefined element.
- // I suppose that he (or she) wants to delete it all
- cursor.remove();
- prev.replace(cursor);
+ gdelete_prev_script();
+ }
+ else if (prev.isG())
+ {
+ gdelete_prev_group();
+ }
+ else if (prev.isC())
+ {
+ // here we also treat the case in which the MACRO is a table
+ gdelete_prev_macro();
}
else
{
- // not handled
+ // not handled. Future cases...
}
-
+
+ logger.debug("gdelete_prev: bye...");
} // end of method
void
}
}
+void
+TPushParser::do_gdelete_script()
+{
+ // If we are here, the cursor is child of a script and
+ // means that a prev MUST exist and that there is only an
+ // element preceding the cursor. The sp's (or sb's) parent
+ // MUST NOT be a MACRO.
+ // The element preceding the cursor is the base of the script.
+
+ logger.debug("do_gdelete_script: start...");
+
+ assert(cursor.parent() && (cursor.parent().isSp() || cursor.parent().isSb()));
+ TNode parent = cursor.parent();
+
+ assert(parent.size() == 2);
+ assert(parent.parent() && !parent.parent().isC());
+
+ TNode prev = cursor.prev();
+ cursor.remove();
+ if (prev.isG() /*&& !prev.hasId()*/ && (prev.size() == 0))
+ {
+ // in this case, the script's base is a group with no elements, so i think
+ // we have to remove the entire MACRO, replacing it with the cursor
+ prev.remove();
+ parent.replace(cursor);
+
+ // if the new parent is a group with Id and the cursor is the only
+ // element of this group, we have to remove it. This controls are made
+ // in the method rgreplace_futher().
+ if (cursor.parent().isG() && cursor.parent().hasId()) rgreplace_futher();
+ }
+ else
+ {
+ // in this case, the prev has to replace the script,
+ // and the curosor has to be placed after the prev.
+ assert(prev.hasId());
+ parent.replace(prev);
+ prev.parent().append(cursor);
+ // now prev should have a preceding element
+ assert(cursor.parent().size() > 1);
+ }
+
+ logger.debug("do_gdelete_script: bye...");
+
+} // end of method do_gdelet_script
+
+void
+TPushParser::do_gdelete_macro()
+{
+ // If we are here, the cursor is a child of a MACRO and this means
+ // that there is an open frame for the control element
+ // and this element is closed at either side (no leftOpen no rightOpen)
+ // and the MACRO was waiting for a non delimited argument, so
+ // we can assert that frame.entry.pattern.size() >= 1
+ assert(cursor.parent() && cursor.parent().isC());
+ TNode parent = cursor.parent();
+
+ assert(!frames.empty());
+ Frame& frame = frames.top();
+ assert(frame.entry.pattern.size() >= 1);
+
+ // we have to take different actions, based on if a preceding element exists
+ // or not
+ logger.debug("do_gdelete_macro:");
+ TNode prev = cursor.prev();
+ if (!prev)
+ {
+ // in this case, a prev does not exist, so the actions of deleting means
+ // that we have to remove the MACRO. So we have to pop the stack.
+ // Being here also means that the MACRO is waiting for the first argument
+ // (which is not delimited)
+ assert(frame.pos == 0);
+ parent.replace(cursor);
+ frames.pop();
+
+ // if the new parent is a group with Id, and has no elements other than the
+ // cursor, we could remove it...but i'm not sure
+ if (cursor.parent() && cursor.parent().isG() && cursor.parent().hasId())
+ rgreplace_futher();
+ else if (cursor.parent().isC())
+ {
+ // We have assumed that a MACRO cannot be a MACRO's child.
+ // At the moment, this assumption is valid, but in a future
+ // it could be false.
+ assert(!frames.empty());
+ Frame& frame = frames.top();
+ assert(frame.pos > 0);
+ frame.pos--;
+ }
+ }
+ else
+ {
+ // we have to control if prev is a delimited argument or not.
+ if (prev.isG() && !prev.hasId())
+ {
+ // in this case, prev is a delimited argument, so we have
+ // to ideally remove the sequence of delimiters
+ Frame& frame = frames.top();
+ assert(frame.pos > 1);
+ logger.debug("do_gdelete_macro: the pos of the frame is: ");
+ cout << frame.pos << endl;
+ logger.debug("do_gdelete_macro: the pattern size of the entry is");
+ cout << frame.entry.pattern.size() << endl;
+ logger.debug("do_gdelete_macro: the prev param is at");
+ cout << frame.entry.previousParam(frame.pos) << endl;
+ cursor.remove();
+ prev.append(cursor);
+ assert(frame.entry.previousParam(frame.pos) != frame.entry.pattern.size());
+ unsigned sequence_length = frame.pos - frame.entry.previousParam(frame.pos) - 1;
+ assert(sequence_length);
+ frame.pos = frame.pos - sequence_length - 1;
+ }
+ else
+ {
+ // the prev is not a delimited argument, so we have to try to remove it.
+ // I told "try" because the prev can be a group or something that
+ // a simple delete cannot remove completely
+ gdelete_prev();
+ }
+ }
+
+ logger.debug("do_gdelete_macro: bye...");
+}
+
+void
+TPushParser::do_gdelete_groupId()
+{
+ // 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 remoev it
+ gdelete_prev();
+
+ // We control if the group has to be removed, because the cursor
+ // could be the only element of the group.
+ if ((parent.first() == cursor) && parent.isG() && parent.hasId())
+ rgreplace_futher();
+
+ }
+ else
+ {
+ // the cursor has no preceding elements, so we have to remove the
+ // group.
+ rgreplace_futher();
+
+ // i have to re-start the process, because it' a graphical delete
+ do_gdelete();
+ }
+
+ logger.debug("do_gdelete_groupId: bye...");
+
+} // end of method do_gdelete_groupId()
+
+void
+TPushParser::do_gdelete_phantom_group()
+{
+ // if we are here, the cursor MUST be a child of a
+ // phantom group.
+ logger.debug("do_gdelete_phantom_group: start");
+ 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)
+ {
+ // the cursor has a preceding element, so we try to remove it
+ logger.debug("do_gdelete_phantom_group: i have to call the gdelete_prev()");
+ gdelete_prev();
+ logger.debug("do_gdelete_phantom_group: gdelete_prev terminated");
+
+ if (parent.size() == 1 && parent.parent().isSp())
+ {
+ logger.debug("do_gdelete_phantom_group: i have to remove a phantom group which is a child of a sp");
+ // in this case the gdelete_prev has removed the only element preceding the cursor.
+ // If the phantom group is a sp's child, it means that the user has removed all \' in the
+ // phantom group. I think, we can remove the phamtom group and the sp element.
+ cursor.remove();
+ parent.replace(cursor);
+ // now we have a sp element with two children: the first child (we don't know nothing about it)
+ // and the cursror.
+ assert(cursor.parent().size() == 2);
+
+ // to delete the script we can invoke the do_gdelete_script(), which will do all controls we need
+ do_gdelete_script();
+ }
+ else if (parent.parent().isSp())
+ {
+ // in this case we have to place the cursor after the sp element
+ logger.debug("do_gdelete_phantom_group: the sequence of \' is not terminated, so i place the cursor after the sp element");
+ cursor.remove();
+ assert(parent.parent().parent());
+ parent.parent().parent().append(cursor);
+ }
+ }
+ else
+ {
+ // in this case the cursor is the only element of the phantom group,
+ // so we have to remove it. But, a phantom group has a special role,
+ // so we have to control the grand futher of the cursor.
+ TNode gfuther = parent.parent();
+ if (!gfuther)
+ {
+ // If here, the TML tree is in an inconsistent state
+ logger.error("do_gdelete_phantom: TML tree in a inconsistent state");
+ }
+ else if (gfuther.isC())
+ {
+ // in this case the phantom group is child of a MACRO.
+ // We have to control the nature of this MACRO.
+ logger.debug("do_gdelete_phantom_group: i have to remove a phantom group which is a child of a MACRO");
+ assert(!frames.empty());
+ 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
+ logger.debug("do_gdelete_phantom_group: the MACRO is leftOpen and rigthOpen");
+ 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());
+ logger.debug("do_gdelete_phantom_group: i have removed the control element, and replaced it with its first child");
+ ggfuther.append(cursor);
+ logger.debug("do_gdelete_phantom_group: cursor appended to the grand grand futher");
+ // 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
+ logger.debug("do_gdelete_phantom_group: the MACRO is rightOpen only");
+ assert(gfuther.size() == 1);
+ assert(frame.pos == 0);
+ 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)
+ {
+ // i think this situation will never occur
+ // but it can be recovered in some way
+ logger.error("the parser has generated a wrong TML tree");
+ }
+ else if (!frame.entry.pattern.empty())
+ {
+ // the MACRO accepts arguments, and the phantom group in which
+ // the cursor is, rappresents a delimited argument
+ // We have to control if the cursor's parent has a preceding element,
+ // or not.
+ logger.debug("do_gdelete_phantom_group: the MACRO accepts arguments");
+ logger.debug("do_gdelete_phantom_group: entry pattern has size:");
+ cout << frame.entry.pattern.size() << endl;
+ TNode uncle = parent.prev();
+ if (!uncle)
+ {
+ // the parent is the only element of the MACRO.
+ // we can assert that frame.pos == 0.
+ // In this case we can replace the MACRO with the cursor
+ assert(frame.pos == 0);
+ cursor.remove();
+ parent.remove();
+ gfuther.replace(cursor);
+ frames.pop();
+ }
+ else
+ {
+ // the parent has a preceding element. Now we have
+ // to control if the uncle is a delimited argument or not.
+ if (uncle.isG() && !uncle.hasId())
+ {
+ // the uncle is a delimited argument. So we have to ideally
+ // remove the sequrnce of delimiters.
+ assert(frame.pos > 1);
+ unsigned sequence_length = frame.pos - frame.entry.previousParam(frame.pos) - 1;
+ assert(frame.entry.previousParam(frame.pos) != frame.entry.pattern.size());
+ assert(sequence_length);
+ // sequence_length is the length of the delimiters sequence which separates
+ // the current parameter and the previous parameter
+ frame.pos = frame.pos - sequence_length - 1;
+ cursor.remove();
+ parent.remove();
+ uncle.append(cursor);
+ }
+ else
+ {
+ // the uncle is a not delimited argument, so we try to remove it.
+ cursor.remove();
+ parent.replace(cursor);
+ parent = cursor.parent(); // i update the parent (it should be the MACRO)
+ assert(parent.isC());
+
+ // now i try to remove the uncle (now it' the preceding element)
+ gdelete_prev();
+ }
+ } // this is the else's end, that handles the case in which an uncle exists
+ } // end of if (!frame.entry.pattern.empty())
+ else
+ {
+ // the entry has no arguments, is not rightOpen and is not leftOpen.
+ logger.warning("do_gdelete_phantom_group: TML tree in a strange state");
+ if (gfuther.size() == 1)
+ {
+ cursor.remove();
+ parent.remove();
+ gfuther.replace(cursor);
+ }
+ else
+ {
+ logger.debug("do_gdelete_phantom_group: TML tree in a very strange state");
+ cursor.remove();
+ gfuther.replace(cursor);
+ }
+ }
+ } // end of if (gfuther.isC())
+ else if (gfuther.is("cell"))
+ {
+ // we have to handle the case where cursor'grand futher is a cell element.
+ // The tables are control sequece, so there is a frame in the stack
+ assert(!frames.empty());
+ assert(frames.top().pos == 1);
+ assert(frames.top().entry.table == 1);
+
+ // a cell MUST be child of row element, which in turn MUST be child of an element
+ // havin attribute table.
+ assert(gfuther.parent() && gfuther.parent().is("row") && gfuther.parent().parent());
+ TNode row = gfuther.parent();
+
+ // in this case the cell has no element, so the user wants to delete this cell.
+ TNode prev_cell = gfuther.prev();
+ cursor.remove();
+ parent.remove();
+ gfuther.remove();
+ // now the cell no longer exists
+
+ if (!prev_cell)
+ {
+ // i this case, the cell is the only cell in the row.
+ // So, i assume that the user wants to delete the entire row.
+ TNode table = row.parent();
+ TNode prev_row = row.prev();
+ row.remove();
+
+ if (!prev_row)
+ {
+ // the row was the only child of the table.
+ // I think have to delete the entire table
+ assert(table.parent());
+ TNode parent_table = table.parent();
+ table.remove();
+ frames.pop();
+ parent_table.append(cursor);
+ }
+ else
+ {
+ // there are other rows (one at least)
+ assert(prev_row.is("row"));
+ assert(prev_row.last());
+ TNode last_cell = prev_row.last();
+ assert(last_cell.is("cell"));
+ assert(last_cell.size() == 1);
+ assert(last_cell.first().isG() && !last_cell.first().hasId());
+ last_cell.first().append(cursor);
+ }
+ } // end of if (!prev_cell)
+ else
+ {
+ // being here means that there is a previous cell,
+ // so we append the cursor to group.
+ assert(prev_cell.size() == 1);
+ assert(prev_cell.first().isG() && !prev_cell.first().hasId());
+ prev_cell.first().append(cursor);
+ }
+ } // end of if (gfuther.is("cell"))
+ else if (gfuther.isSp())
+ {
+ // in this case, the user pushed a \'. So this phantom group
+ // contained a sequence of \'.
+ // Maybe in this part will never be used, because, if we delete last \' in the
+ // phantom group, we remove the phantom group also
+ //
+ // In any case, if we are here we have two choice:
+ // delete the phantom group;
+ // delete the superscript.
+ }
+ else
+ {
+ // cursor' grand futher is undefined
+ logger.error("do_gdelete_phantom_group: TML tree in a unknown state");
+ }
+ } // end of the else of the if (prev)
+
+ if (!frames.empty())
+ {
+ logger.debug("do_gdelete_phantom_group: the stack is not empty");
+ logger.debug("do_gdelte_phanto_group: is the top element rightOpen?");
+ cout << frames.top().entry.rightOpen << endl;
+ logger.debug("do_gdelte_phanto_group: is the top element'pattern empty?");
+ cout << frames.top().entry.pattern.empty() << endl;
+ }
+ logger.debug("do_gdelete_phantom_group: bye...");
+}
+
+
+void
+TPushParser::do_gdelete()
+{
+ logger.debug("do_gdelete: start");
+ // we have to handle the case in wich the cursor has a parent or not
+ if (!cursor.parent())
+ {
+ // it's not a good situation...at the moment we do not take actions
+ logger.error("TML tree not well structured");
+ }
+ else
+ {
+ // a parent exists. We have to take differnt actions, based on the nature of
+ // the parent
+ TNode parent = cursor.parent();
+ if (parent.is("math"))
+ {
+ // we ca do two thing...remove the math mode (it implies controlling the display attribute), do nothing
+ // At the moment, the user's will of deleting is simply ignored
+ logger.error("TML tree not well structured");
+ }
+ else if (parent.isG())
+ {
+ // the cursor's parent is a group. We have to control if it's a phantom group or not
+ logger.debug("do_gdelete: the cursor's parent is a group");
+ if (parent.hasId())
+ {
+ logger.debug("do_gdelete: which has Id");
+ do_gdelete_groupId();
+ }
+ else
+ {
+ logger.debug("do_gdelete: which is a phantom group");
+ do_gdelete_phantom_group();
+ }
+ } // end of parent is group
+ else if (parent.isC())
+ {
+ cout << "the cursor's parent is a MACRO" << endl;
+ do_gdelete_macro();
+ } // end of parent is a MACRO
+ else if (parent.isSp() || parent.isSb())
+ {
+ cout << "the cursor's parent is a script" << endl;
+ do_gdelete_script();
+ } // end of parent is sp or sb
+ } // end of the else which consider the case in which parent exists
+
+ if (!cursor.parent())
+ logger.debug("do_gdelete: the cursro has no parent -> paolo is stupid");
+
+ if (!frames.empty())
+ {
+ logger.debug("do_gdelete: the stack is not empty");
+ logger.debug("do_gdelete: is the top element rightOpen?");
+ cout << frames.top().entry.rightOpen << endl;
+ logger.debug("do_gdelete: is the top element'pattern empty");
+ cout << frames.top().entry.pattern.empty() << endl;
+ }
+ logger.debug("do_gdelete: bye...");
+
+} // end of method do_gdelete
+
+/*
void
TPushParser::do_gdelete()
{
// 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;
+ cout << "do_gdelete: i have to remove a phantom group which is a child of a MACRO" << endl;
Frame& frame = frames.top();
+ cout << frame.entry.leftOpen << frame.entry.rightOpen << endl;
if (frame.entry.leftOpen && frame.entry.rightOpen)
{
// in this case, the cursor is in the second and last child
{
// in this case, we can assert that frame in the stack has
// pos greater than 0
+ cout << "this is the assert that fails" << endl;
assert(frame.pos > 0);
// cursor's uncle does exist. we have to control
TNode prev = cursor.prev();
cursor.remove();
- if (prev.isG() /*&& !prev.hasId()*/ && (prev.size() == 0))
+ if (prev.isG()*/ /*&& !prev.hasId()*/ /* && (prev.size() == 0))
{
prev.remove();
parent.replace(cursor);
}
} // end of method
+*/
void
TPushParser::process(const TToken& token)
void
TPushParser::push(const TToken& token)
{
- cerr << "TPushParser::push " << token.value << " (cat: " << token.category << ")" << endl;
+ logger.debug("TPushParser::push " + token.value + " (cat: ");
+ cout << token.category << ")" << endl;
if (token.category == TToken::GDELETE)
{
- cout << "push: i have to process a token with category member = GDELETE" << endl;
+ logger.debug("push: i have to process a token with category member = GDELETE");
process(token);
}
- else if ((doc.root().first() && doc.root().first().is("math")) || token.category == TToken::SHIFT)
+ else
{
+ logger.debug("push: i get the cursor's parent");
TNode parent = cursor.parent();
// If the cursor has no parent then it is detached from the editing
// tree, which means this token will be ignored
if (parent.isG() && !parent.hasId() && parent.parent().isC())
{
// There must be an open frame, for the grand-parent is a control sequence
+ logger.debug("push: cursor'parent is a phantom group, and this group has a MACRO as parent");
+ logger.debug("push: i assert that !frames.empty()");
assert(!frames.empty());
+ logger.debug("push: this assert is OK");
+ logger.debug("push: now i take the top element of the stack");
Frame& frame = frames.top();
+ logger.debug("push: now i've got the top element");
if (!frame.entry.pattern.empty())
{
// The entry pattern is not empty. By our conventions this means
// the entry cannot be open at either end, hence we are parsing
// a delimited argument
+ logger.debug("push: the frame.entry accepts arguments");
assert(frame.pos + 1 < frame.entry.pattern.size());
assert(frame.entry.pattern[frame.pos + 1].category != TToken::PARAMETER);
if (frame.entry.pattern[frame.pos + 1] == token)
// entry. What happens if we actually are in the left side?
// This could happen only when re-editing an entered expression
// We'll see...
+ logger.debug("push: the frame.entry has no arguments, so i assert that i's rightOpne");
assert(frame.entry.rightOpen);
+ logger.debug("push: this assert is OK, now i process the token");
process(token);
+ logger.debug("push: the token has been processed");
}
}
else if (parent.isC())
// it will be important for the parser to know that the entry
// has been completed in order to place the cursor correctly
// in the next position
+ logger.debug("TPushParser.push: we should be here");
frame.pos++;
process(token);
}
{
cout << "ignored token" << endl;
}
-
- //if (listener) listener->callback(doc); //it shoul be repristened if you remove the comment in the else above
- } // this end corresponds to the if ((doc.root().first() && doc.root().first().is("math")) || token.category == TToken::SHIFT)
- else
- {
- // there is no math element
- // In this case, i think we have to emit an error
- cout << "push: ignored token...you have to enter in math mode...insert $" << endl;
- }
+ } // this end corresponds to the else of the if (token.category == TToken::GDELETE)
if (factory) factory->documentModified(doc);
if (frames.empty()) cout << "stack vuoto" << endl;
- else cout << "stack non vuoto" << endl;
+ else
+ {
+ logger.debug("push: the stack is not empty");
+ logger.debug("push: is the top element rightOpen?");
+ cout << frames.top().entry.rightOpen << endl;
+ logger.debug("push: is the pattern empty");
+ cout << frames.top().entry.pattern.empty() << endl;
+ }
}
void