Frames | No Frames |
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: }