]> matita.cs.unibo.it Git - helm.git/blobdiff - helm/DEVEL/mathml_editor/src/TPushParser.cc
Now it's possible to insert and delete control sequence with arguments
[helm.git] / helm / DEVEL / mathml_editor / src / TPushParser.cc
index a063668e0ae31dd03e44f2719733276aa52cda7a..d3dd893d73c494ad8b6648fd4ae74242b557349f 100644 (file)
@@ -68,12 +68,16 @@ TPushParser::do_end()
     }
   else if (parent && parent.isG() && parent.parent() && parent.parent().is("cell"))
     {
+      assert(!frames.empty());
       // closing brace for a structure in which & or \cr have been used
       TNode row = parent.parent().parent();
       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();
     }
   else if (parent && parent.isG() && !parent.hasId() && parent.parent())
     {
@@ -452,9 +456,13 @@ TPushParser::do_control(const std::string& name)
                if (parent.isG())
                  {
                    frames.push(Frame(entry));
-                   cout << "do_control: valore di pos del frame inserito " << frames.top().pos << endl;
+
+                   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);
@@ -532,7 +540,7 @@ TPushParser::gdelete_prev()
       prev.append(cursor);
       do_gdelete();
     }
-  else if (prev.isC())
+  else if (prev.isC() && dictionary.find(prev["name"]).cls != TDictionary::UNDEFINED)
     {
       const TDictionary::Entry& entry = dictionary.find(prev["name"]);
 
@@ -581,8 +589,11 @@ TPushParser::gdelete_prev()
              prev.last().append(cursor);
              // i have to push a frame with a correct value of pos
              Frame frame(entry);
-             frame.pos = entry.pattern.size() - 2;
+             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;
            }
          else
            {
@@ -591,17 +602,32 @@ TPushParser::gdelete_prev()
              // remove it
              cout << "gdelete_prev: i try to remove the last argumet of the MACRO" << endl;
              cursor.remove();
-             prev.append(cursor); // now prev is the cursor's parent
+             if (entry.table == 1 && prev.last().is("row"))
+               {
+                 // in this case should be appended to the group associated to 
+                 // the last cell of the last row of the table
+                 assert(prev.last().last().is("cell") && prev.last().last().first().isG());
+                 prev.last().last().first().append(cursor);
+               }
+             else prev.append(cursor);
 
              Frame frame(entry);
              frame.pos = entry.pattern.size();
              frames.push(frame);
              
-             gdelete_prev();
+             if (cursor.prev()) gdelete_prev();
+             else do_gdelete();
 
            }
        }
     }
+  else if (dictionary.find(prev["name"]).cls == TDictionary::UNDEFINED)
+    {
+      // The user wants to delete an undefined element.
+      // I suppose that he (or she) wants to delete it all
+      cursor.remove();
+      prev.replace(cursor);
+    }
   else 
     {
       // not handled
@@ -758,14 +784,20 @@ TPushParser::do_gdelete()
                                  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
+                                     // the cursor's uncle is a phantom group, so it was a 
+                                     // delimited argument of the MACRO and the corrisponding sequence of 
+                                     // delimeters is inserted. So, the action of deleting means
+                                     // removing this sequence
+                                     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);
-                                     frame.pos -= 2;
                                    }
                                  else
                                    {
@@ -797,6 +829,65 @@ TPushParser::do_gdelete()
                            
                            }
                        }
+                     else if (gfuther.is("cell"))
+                       {
+                         // being here means that there is a frame in the stack 
+                         // associated to the "table"
+                         cout << "do_gdelete: i have to delete a cell" << endl;
+                         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);
+                               }
+                           }
+                         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);
+                           }
+                       }
                    }
                  else // the grand futher is math
                    {
@@ -848,12 +939,16 @@ TPushParser::do_gdelete()
              if (prev.isG() && !prev.hasId())
                {
                  // in this case we have to append the cursor 
-                 // to the prev and decrement frame.pos of two units
-                 // because the prev is a delimited argument and the 
-                 // delimiter is inserted. So we ideally remove this delimiter
+                 // to the prev and decrement frame.pos of the length of 
+                 // delimiters sequence that delimitates the preceding argument.
+                 // So we ideally remove this sequence
+                 assert(frame.pos > 1);
                  cursor.remove();
                  prev.append(cursor);
-                 frame.pos -=2;
+                 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
                {
@@ -867,14 +962,14 @@ TPushParser::do_gdelete()
         {
          // being here means that a prev MUST exist 
          // and that there is only an element preceding the cursor.
-         // A sp's (or sb's) MUST NOT be a MACRO
+         // The sp's (or sb's) parent MUST NOT be a MACRO
 
          assert(parent.size() == 2);
          assert(parent.parent() && !parent.parent().isC());
          
          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);
@@ -900,7 +995,7 @@ TPushParser::do_gdelete()
     }
   else
     {
-      // the cursro has no parent!!!
+      // the cursor has no parent!!!
       // do nothing?
       // emit an error? and if we want to emit an error, in which way?
     }
@@ -941,132 +1036,160 @@ TPushParser::push(const TToken& token)
       cout << "push: i have to process a token with category member = GDELETE" << endl;
       process(token);
     }
-  else
+  else if ((doc.root().first() && doc.root().first().is("math")) || token.category == TToken::SHIFT)
     {
 
-  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)
-    // If the parent is a phantom group and the grand-parent is a
-    // control sequence, there are two cases:
-    // a. we are parsing a delimited argument of a entry
-    // b. we are parsing a side of a right- or left-open entry
-    if (parent.isG() && !parent.hasId() && parent.parent().isC())
-      {
-       // There must be an open frame, for the grand-parent is a control sequence
-       assert(!frames.empty());
-       Frame& frame = frames.top();
-       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
-           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)
+      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)
+        // If the parent is a phantom group and the grand-parent is a
+        // control sequence, there are two cases:
+        // a. we are parsing a delimited argument of a entry
+        // b. we are parsing a side of a right- or left-open entry
+        if (parent.isG() && !parent.hasId() && parent.parent().isC())
+          {
+           // There must be an open frame, for the grand-parent is a control sequence
+           assert(!frames.empty());
+           Frame& frame = frames.top();
+           if (!frame.entry.pattern.empty())
              {
-               // The token matches with the delimiter of the argument.
-               cursor.remove();
-
-               // If the phantom group has just one child, it is not necessary
-               // and can be removed. However, this would complicate
-               // all the code that follows, so given it is a rare case we
-               // leave it alone
-               // if (parent.size() == 1) parent.replace(parent[0]);
-
-               // Eat both the argument and its delimiter
-               frame.pos += 2;
-               if (frame.pos == frame.entry.pattern.size())
-                 {
-                   // This token has completed the entry
-                   advance(parent.parent());
-                 }
-               else if (frame.entry.paramDelimited(frame.pos))
-                 {
-                   // For the next is a delimited argument we have to place
-                   // a suitable phantom group with the cursor inside
-                   TNode g = doc.createG();
-                   parent.parent().append(g);
-                   g.append(cursor);
-                 }
-               else
-                 parent.parent().append(cursor);
+               // 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
+               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)
+                 {
+                   // The token matches with a delimiter of the argument, 
+                   // so we increment the frame.pos
+                   frame.pos++;
+
+                   if (frame.entry.lastDelimiter(frame.pos))
+                     {
+                       // this delimiter is the last one for the argumet, 
+                       // so the argument is completed
+                       cursor.remove();
+                       frame.pos++;
+
+                       if (frame.pos == frame.entry.pattern.size())
+                         {
+                           // This token has completed the entry
+                           frames.pop();
+                           advance(parent.parent());
+                         }
+                       else if (frame.entry.paramDelimited(frame.pos))
+                         {
+                           // For the next is a delimited argument we have to place
+                           // a suitable phantom group with the cursor inside
+                           TNode g = doc.createG();
+                           parent.parent().append(g);
+                           g.append(cursor);
+                         }
+                       else
+                         parent.parent().append(cursor);
+                     }
+                 }
+               else
+                 {
+                   // Delimiter mismatch.
+                   if (frame.entry.pattern[frame.pos].category != TToken::PARAMETER)
+                     {
+                       // in this case, there is a sequence of delimiters that delimitates
+                       // the argument, and the user correctly inserted a portion of this 
+                       // sequence, but has inserted a wrong delimiter.
+                       // Here, there are some possibilities:
+                       //   - ignore the token, and wait for the correct delimiter
+                       //   - ignore the token, wait for the correct delimiter and emit an error
+                       // If we want to emit an error, we shlould implement a class, that handle 
+                       // the error.
+                       // At the moment, the error is printed to screen
+                       cout << "push: it's not the correct delimiter...you have to type " << frame.entry.pattern[frame.pos + 1].value << endl;
+                     }
+                   else
+                     {
+                       // in this case, the sequence of delimiters is composed of one 
+                       // delimiter. It means that we have to process the token
+                       process(token);
+                     }
+                 }
              }
            else
              {
-               // Delimiter mismatch. Since we are parsing a delimited
-               // argument we just process the token
-               process(token);
+               // The entry pattern is empty, hence we are parsing a right-open
+               // entry. What happens if we actually are in the left side?
+               // This could happen only when re-editing an entered expression
+               // We'll see...
+               assert(frame.entry.rightOpen);
+               process(token);
              }
-         }
-       else
-         {
-           // The entry pattern is empty, hence we are parsing a right-open
-           // entry. What happens if we actually are in the left side?
-           // This could happen only when re-editing an entered expression
-           // We'll see...
-           assert(frame.entry.rightOpen);
-           process(token);
-         }
-      }
-    else if (parent.isC())
-      {
-       // We are parsing a non-delimited argument entry
-       // or a fixed token
-       Frame& frame = frames.top();
-       assert(frame.pos < frame.entry.pattern.size());
-
-       cout << "push: il valore di pos del frame inserito prima e': " << frame.pos <<  endl;
-       if (frame.entry.pattern[frame.pos].category == TToken::PARAMETER)
-         {
-           // As by the TeX parsing rules of undelimited parameters,
-           // empty spaces are ignored
-           if (token.category != TToken::SPACE)
+          }
+        else if (parent.isC())
+          {
+           // We are parsing a non-delimited argument entry
+           // or a fixed token
+           Frame& frame = frames.top();
+           assert(frame.pos < frame.entry.pattern.size());
+
+           cout << "push: there is a frame with pos " << frame.pos <<  endl;
+           if (frame.entry.pattern[frame.pos].category == TToken::PARAMETER)
              {
-               // We need to increase the frame position here, becase inside
-               // process the function advance will be called. At that point
-               // 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
-               frame.pos++;
-               process(token);
+               // As by the TeX parsing rules of undelimited parameters,
+               // empty spaces are ignored
+               if (token.category != TToken::SPACE)
+                 {
+                   // We need to increase the frame position here, becase inside
+                   // process the function advance will be called. At that point
+                   // 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
+                   frame.pos++;
+                   process(token);
+                 }
              }
-         }
-       else if (frame.entry.pattern[frame.pos] == token)
-         {
-           // The token has been accepted
-           frame.pos++;
-           if (frame.pos < frame.entry.pattern.size() &&
-               frame.entry.paramDelimited(frame.pos))
+           else if (frame.entry.pattern[frame.pos] == token)
              {
-               // If the next is a delimited argument we have to place
-               // the phantom group with the cursor inside
-               TNode g = doc.createG();
-               cursor.replace(g);
-               g.append(cursor);
+               // The token has been accepted
+               frame.pos++;
+               if (frame.pos < frame.entry.pattern.size() &&
+                   frame.entry.paramDelimited(frame.pos))
+                 {
+                   // If the next is a delimited argument we have to place
+                   // the phantom group with the cursor inside
+                   TNode g = doc.createG();
+                   cursor.replace(g);
+                   g.append(cursor);
+                 }
+               else
+                 advance(parent);
              }
            else
-             advance(parent);
-         }
-       else
-         {
-           // There is a mismatch. Emit an error and ignore the token?
-           cerr << "ERROR: token ignored: " << token.value << " (cat: " << token.category << ")" << endl;
-         }
+             {
+               // There is a mismatch. Emit an error and ignore the token?
+               cerr << "ERROR: token ignored: " << token.value << " (cat: " << token.category << ")" << endl;
+             }
 
-      }
-    else
-      process(token);
+          }
+        else
+          process(token);
+      else
+        {
+          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
     {
-      cout << "ignored token" << endl;
+      // 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 == GDELETE)
 
-  if (listener) listener->callback(doc);
+  //if (listener) listener->callback(doc);
 
   if (frames.empty()) cout << "stack vuoto" << endl;
   else cout << "stack non vuoto" << endl;