OSDN Git Service

Initial revision
[pf3gnuchains/gcc-fork.git] / libjava / classpath / gnu / javax / swing / text / html / parser / models / list.java
1 /* list.java --
2    Copyright (C) 2005 Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37
38
39 package gnu.javax.swing.text.html.parser.models;
40
41 import java.io.Serializable;
42
43 /**
44  * Part of the internal representation of the content model.
45  * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
46  */
47 public class list
48   extends node
49   implements Serializable
50 {
51   private static final long serialVersionUID = 1;
52
53   /**
54    * Setting to true means that the list nodes must always be connected
55    * by the same operation. This is far safer and clearer, but not
56    * required by default standard.
57    */
58   public static boolean CLEAR;
59
60   /**
61    * A list of nodes.
62    */
63   public final node[] nodes;
64
65   /**
66    * Creates a new model list that is a member of some enclosing list.
67    * @param binary_operator An operator with that this list is connected
68    * with other members of the enclosing list.
69    * @param unary_operator The unary operator for this list.
70    * @param a_nodes The nodes inside this list.
71    */
72   public list(char binary_operator, char unary_operator, node[] a_nodes)
73   {
74     super(binary_operator, unary_operator, a_nodes);
75     nodes = a_nodes;
76   }
77
78   /**
79    * Creates a new model list. Assigns the previous field.
80    * @param a_nodes The nodes for this list.
81    * @throws an error if the node elements are connected by the
82    * different operations. This is not supported, use grouping.
83    */
84   public list(node[] a_nodes)
85        throws Error
86   {
87     this(',', (char) 0, a_nodes);
88
89     int operation = nodes [ 0 ].binary;
90
91     for (int i = 0; i < nodes.length; i++)
92       {
93         if (CLEAR && nodes [ i ].binary != operation)
94           throw new Error("List members can only be connected by " +
95                           "the same operation, use grouping"
96                          );
97
98         if (i > 0)
99           nodes [ i ].previous = nodes [ i - 1 ];
100       }
101   }
102
103   /**
104    * Returns true if all members in the list are closed.
105    */
106   public boolean isClosed()
107   {
108     if (super.isClosed())
109       return true;
110     for (int i = 0; i < nodes.length; i++)
111       {
112         if (!nodes [ i ].isClosed())
113           return false;
114       }
115     return true;
116   }
117
118   /**
119    * Find the token that could match as the next token in
120    * the token list.
121    *
122    * @return Such token object or null if none is found.
123    */
124   public Object findFreeNode()
125   {
126     Object fn;
127     for (int j = 0; j < nodes.length; j++)
128       {
129         if (!nodes [ j ].isClosed())
130           {
131             fn = nodes [ j ].findFreeNode();
132             if (fn != null)
133               return fn;
134           }
135       }
136     return null;
137   }
138
139   /**
140    * Tries to match this list agains the given token sequence.
141    * @param tokens the sequence of the tokens to match.
142    * @return true if the valid match is found.
143    */
144   public boolean matches(Object[] tokens)
145   {
146     reset();
147
148     Object x;
149     boolean m;
150     boolean matched = false;
151
152     for (int i = 0; i < tokens.length; i++)
153       {
154         matched = false;
155         x = tokens [ i ];
156
157         nodescan: 
158         for (int j = 0; j < nodes.length; j++)
159           {
160             if (!nodes [ j ].isClosed())
161               {
162                 m = nodes [ j ].performMatch(x);
163
164                 if (m)
165                   {
166                     matched = true;
167                     break nodescan;
168                   }
169               }
170           }
171         if (!matched)
172           return false;
173       }
174
175     boolean valid = true;
176
177     for (int i = 0; i < nodes.length; i++)
178       {
179         if (!nodes [ i ].valid())
180           valid = false;
181       }
182
183     return valid;
184   }
185
186   /**
187    * The list never closes, despite it is trated as closed
188    * if all members in the list are closed.
189    * @return false.
190    */
191   public boolean mustClose()
192   {
193     return false;
194   }
195
196   /**
197    * Perform a match operation for the single token
198    * against this list.
199    * @param token a token to match.
200    * @return true if the match is found.
201    */
202   public boolean performMatch(Object token)
203   {
204     boolean ok = false;
205     Matching: 
206     for (int i = 0; i < nodes.length; i++)
207       {
208         ok = nodes [ i ].performMatch(token);
209
210         if (ok)
211           break Matching;
212       }
213
214     if (ok)
215       matches();
216
217     return ok;
218   }
219
220   /**
221    * Prepeares the list for the next matching operation.
222    */
223   public void reset()
224   {
225     super.reset();
226     for (int i = 0; i < nodes.length; i++)
227       nodes [ i ].reset();
228   }
229
230   /**
231    * Check if the provided token can match as a next token in the
232    * list. In the case of match, the list state changes, moving
233    * current position after the matched token. However if this method
234    * returns a suggested new token to insert before the provided one,
235    * the state of the list does not change.
236    * @return Boolean.TRUE if the match is found,
237    * Boolean.FALSE if the match is not possible and no token can be
238    * inserted to make the match valid. Otherwise, returns the
239    * token object that can be inserted before the last token in the
240    * list, probably (not for sure) making the match valid.
241    * If the object is an instance of Element or TagElement,
242    * it is first ensured that the object flag "omit start" is set.
243    */
244   public Object show(Object x)
245   {
246     boolean m;
247     boolean matched = false;
248
249     nodescan: 
250     for (int j = 0; j < nodes.length; j++)
251       {
252         if (!nodes [ j ].isClosed())
253           {
254             m = nodes [ j ].performMatch(x);
255
256             if (m)
257               {
258                 matched = true;
259                 break nodescan;
260               }
261             else
262               {
263                 // For comma operation, only first not closed
264                 // node must be tested for a match.
265                 // unless it allows matching zero times.
266                 if (binary == ',' &&
267                     !(nodes [ j ].unary == '?' || nodes [ j ].unary == '*')
268                    )
269                   break nodescan;
270               }
271           }
272       }
273
274     if (!matched)
275       {
276         // Find and return that would be matched.
277         Object freeNode = findFreeNode();
278         if (freeNode == null)
279           return Boolean.FALSE;
280         else
281           return freeNode;
282       }
283
284     for (int i = 0; i < nodes.length; i++)
285       if (!nodes [ i ].validPreliminary())
286         {
287           return Boolean.FALSE;
288         }
289
290     return Boolean.TRUE;
291   }
292
293   /**
294    * Returns a string representation of the list.
295    * @return String representation, similar to BNF expression.
296    */
297   public String toString()
298   {
299     StringBuffer b = new StringBuffer();
300     b.append(" ( ");
301     for (int i = 0; i < nodes.length; i++)
302       {
303         if (i > 0)
304           b.append(" " + (char) nodes [ i ].binary + " ");
305         b.append(nodes [ i ]);
306       }
307
308     b.append(" )");
309     if (unary != 0)
310       b.append((char) unary);
311     else
312       b.append(' ');
313     return b.toString();
314   }
315
316   /**
317    * Returns true if all memebers in the list are valid.
318    */
319   public boolean valid()
320   {
321     for (int i = 0; i < nodes.length; i++)
322       {
323         if (!nodes [ i ].valid())
324           return false;
325       }
326     return true;
327   }
328
329   /**
330    * Returns true if all memebers in the list are either valid
331    * or unvisited. The unvisited members can become valid after
332    * more tokens will be shown.
333    */
334   public boolean validPreliminary()
335   {
336     if (silenceAllowed())
337       {
338         boolean everVisited = false;
339         for (int i = 0; i < nodes.length; i++)
340           {
341             if (nodes [ i ].visits > 0)
342               {
343                 everVisited = true;
344                 break;
345               }
346           }
347         if (!everVisited)
348           return true;
349       }
350
351     for (int i = 0; i < nodes.length; i++)
352       {
353         if (!nodes [ i ].validPreliminary())
354           return false;
355       }
356     return true;
357   }
358
359   /**
360    * Closes all members in the list.
361    */
362   protected void close()
363   {
364     super.close();
365     for (int i = 0; i < nodes.length; i++)
366       {
367         nodes [ i ].close();
368       }
369   }
370
371   /**
372    * Compare given token with the token of this node.
373    * If the token represents a <code>list</code>, the call may be
374    * delegeted to the child subnodes.
375    * @param a_token A token to compare.
376    * @return True if the token matches the token of this node.
377    */
378   protected boolean compare(Object a_token)
379   {
380     return performMatch(a_token);
381   }
382 }