|
BasicPatternElement |
|
1 /* 2 * BasicPatternElement.java - transducer class 3 * 4 * Copyright (c) 1998-2001, The University of Sheffield. 5 * 6 * This file is part of GATE (see http://gate.ac.uk/), and is free 7 * software, licenced under the GNU Library General Public License, 8 * Version 2, June 1991 (in the distribution as file licence.html, 9 * and also available at http://gate.ac.uk/gate/licence.html). 10 * 11 * Hamish Cunningham, 24/07/98 12 * 13 * $Id: BasicPatternElement.java,v 1.12 2001/10/25 15:23:37 cursu Exp $ 14 */ 15 16 17 package gate.jape; 18 19 import java.util.*; 20 import gate.annotation.*; 21 import gate.util.*; 22 import gate.*; 23 24 25 /** 26 * A pattern element within curly braces. Has a set of Constraint, 27 * which all must be satisfied at whatever position the element is being 28 * matched at. 29 */ 30 public class BasicPatternElement 31 extends PatternElement implements JapeConstants, java.io.Serializable 32 { 33 /** Debug flag */ 34 private static final boolean DEBUG = false; 35 36 /** A set of Constraint. Used during parsing. */ 37 private ArrayList constraints1; 38 39 /** A set of Constraint. Used during matching. */ 40 private Constraint[] constraints2; 41 42 /** A map of constraint annot type to constraint. Used during parsing. */ 43 private HashMap constraintsMap; 44 45 /** Cache of the last position we failed at (-1 when none). */ 46 private int lastFailurePoint = -1; 47 48 /** The position of the next available annotation of the type required 49 * by the first constraint. 50 */ 51 //private MutableInteger nextAvailable = new MutableInteger(); 52 53 /** The set of annotations we have matched. */ 54 private AnnotationSet matchedAnnots; 55 56 /** Access to the annotations that have been matched. */ 57 public AnnotationSet getMatchedAnnots() { return matchedAnnots; } 58 59 /** Construction. */ 60 public BasicPatternElement() { 61 constraintsMap = new HashMap(); 62 constraints1 = new ArrayList(); 63 lastFailurePoint = -1; 64 //nextAvailable = new MutableInteger(); 65 matchedAnnots = new AnnotationSetImpl((Document) null); 66 } // construction 67 68 /** Need cloning for processing of macro references. See comments on 69 * <CODE>PatternElement.clone()</CODE> 70 */ 71 public Object clone() { 72 BasicPatternElement newPE = (BasicPatternElement) super.clone(); 73 newPE.constraintsMap = (HashMap) constraintsMap.clone(); 74 newPE.constraints1 = new ArrayList(); 75 int consLen = constraints1.size(); 76 for(int i = 0; i < consLen; i++) 77 newPE.constraints1.add( 78 ((Constraint) constraints1.get(i)).clone() 79 ); 80 // newPE.matchedAnnots = new AnnotationSetImpl((Document) null); 81 // newPE.matchedAnnots.addAll(matchedAnnots); 82 return newPE; 83 } // clone 84 85 /** Add a constraint. Ensures that only one constraint of any given 86 * annotation type exists. 87 */ 88 public void addConstraint(Constraint newConstraint) { 89 /* if the constraint is already mapped, put it's attributes on the 90 * existing constraint, else add it 91 */ 92 String annotType = newConstraint.getAnnotType(); 93 Constraint existingConstraint = (Constraint) constraintsMap.get(annotType); 94 if(existingConstraint == null) { 95 constraintsMap.put(annotType, newConstraint); 96 constraints1.add(newConstraint); 97 } 98 else { 99 FeatureMap newAttrs = newConstraint.getAttributeSeq(); 100 FeatureMap existingAttrs = 101 existingConstraint.getAttributeSeq(); 102 existingAttrs.putAll(newAttrs); 103 if(newConstraint.isNegated()) 104 existingConstraint.negate(); 105 } 106 } // addConstraint 107 108 109 /** Finish: replace dynamic data structures with Java arrays; called 110 * after parsing. 111 */ 112 public void finish() { 113 int j=0; 114 constraints2 = new Constraint[constraints1.size()]; 115 for(Iterator i=constraints1.iterator(); i.hasNext(); ) { 116 constraints2[j] = (Constraint) i.next(); 117 constraints2[j++].finish(); 118 } 119 constraints1 = null; 120 } // finish 121 122 /** Reset: clear last failure point and matched annotations list. */ 123 public void reset() { 124 super.reset(); 125 lastFailurePoint = -1; 126 //nextAvailable.value = -1; 127 matchedAnnots = new AnnotationSetImpl((Document) null); 128 } // reset 129 130 /** Multilevel rollback of the annotation cache. */ 131 public void rollback(int arity) { 132 //Debug.pr(this, "BPE rollback(" + arity + "), matchHistory.size() = " + 133 // matchHistory.size()); 134 //Debug.nl(this); 135 136 for(int i=0; i<arity; i++) { 137 matchedAnnots.removeAll((AnnotationSet) matchHistory.pop()); 138 } 139 } // rollback 140 141 /** Does this element match the document at this position? */ 142 public boolean matches ( 143 Document doc, int position, MutableInteger newPosition 144 ) { 145 final int startingCacheSize = matchedAnnots.size(); 146 AnnotationSet addedAnnots = new AnnotationSetImpl((Document) null); 147 148 //Debug.pr(this, "BPE.matches: trying at position " + position); 149 //Debug.nl(this); 150 int rightmostEnd = -1; 151 int end = doc.getContent().size().intValue(); 152 MutableInteger nextAvailable = new MutableInteger(); 153 int nextAvailOfFirstConstraint = -1; 154 155 for(int len = constraints2.length, i = 0; i < len; i++) { 156 Constraint constraint = constraints2[i]; 157 String annotType = constraint.getAnnotType(); 158 JdmAttribute[] constraintAttrs = constraint.getAttributeArray(); 159 MutableBoolean moreToTry = new MutableBoolean(); 160 161 if(DEBUG) { 162 Out.println( 163 "BPE.matches: selectAnn on lFP = " + lastFailurePoint + 164 "; max(pos,lfp) = " + Math.max(position, lastFailurePoint) + 165 "; annotType = " + annotType + "; attrs = " + 166 constraintAttrs.toString() + Strings.getNl() 167 ); 168 for(int j=0; j<constraintAttrs.length; j++) 169 Out.println( 170 "BPE.matches attr: " + constraintAttrs[j].toString() 171 ); 172 } 173 FeatureMap features = Factory.newFeatureMap(); 174 for(int j = constraintAttrs.length - 1; j >= 0; j--) 175 features.put(constraintAttrs[j].getName(), constraintAttrs[j].getValue()); 176 AnnotationSet match = doc.getAnnotations().get( 177 // this loses "April 2" on the frozen tests: 178 // Math.max(nextAvailable.value, Math.max(position, lastFailurePoint)), 179 annotType, 180 features, 181 new Long(Math.max(position, lastFailurePoint)) /*, 182 nextAvailable, 183 moreToTry */ 184 ); 185 if(DEBUG) Out.println( 186 "BPE.matches: selectAnn returned " + match + ".... moreToTry = " + 187 moreToTry.value + " nextAvailable = " + nextAvailable.value 188 ); 189 190 // store first constraint's next available 191 if(nextAvailOfFirstConstraint == -1) 192 nextAvailOfFirstConstraint = nextAvailable.value; 193 194 // if there are no more annotations of this type, then we can 195 // say that we failed this BPE and that we tried the whole document 196 if(! moreToTry.value) { 197 if(match != null) 198 throw(new RuntimeException("BPE: no more annots but found one!")); 199 lastFailurePoint = end; 200 newPosition.value = end; 201 } 202 203 // selectNextAnnotation ensures that annotations matched will 204 // all start >= position. we also need to ensure that second and 205 // subsequent matches start <= to the rightmost end. otherwise 206 // BPEs can match non-contiguous annotations, which is not the 207 // intent. so we record the rightmostEnd, and reject annotations 208 // whose leftmostStart is > this value. 209 int matchEnd = -1; 210 if(match != null) { 211 matchEnd = match.lastNode().getOffset().intValue(); 212 if(rightmostEnd == -1) { // first time through 213 rightmostEnd = matchEnd; 214 } 215 else if(match.firstNode().getOffset().intValue() >= rightmostEnd) { 216 // reject 217 lastFailurePoint = matchEnd; 218 match = null; 219 } 220 else { // this one is ok; reset rightmostEnd 221 if(rightmostEnd < matchEnd) 222 rightmostEnd = matchEnd; 223 } 224 } // match != null 225 226 // negation 227 if(constraint.isNegated()) { 228 if(match == null) { 229 //Debug.pr( 230 // this, "BPE.matches: negating failed constraint" + Debug.getNl() 231 //); 232 continue; 233 } 234 else { 235 // Debug.pr( 236 // this, "BPE.matches: negating successful constraint, match = " + 237 // match.toString() + Debug.getNl() 238 //); 239 lastFailurePoint = matchEnd; 240 match = null; 241 } 242 } // constraint is negated 243 244 if(match == null) { // clean up 245 //Debug.pr(this, "BPE.matches: selectNextAnnotation returned null"); 246 //Debug.nl(this); 247 248 newPosition.value = Math.max(position + 1, nextAvailOfFirstConstraint); 249 lastFailurePoint = nextAvailable.value; 250 251 // we clear cached annots added this time, not all: maybe we were 252 // applied under *, for example, and failure doesn't mean we should 253 // purge the whole cache 254 //for(int j = matchedAnnots.size() - 1; j >= startingCacheSize; j--) 255 // matchedAnnots.removeNth(j); 256 matchedAnnots.removeAll(addedAnnots); 257 258 //Debug.pr( 259 // this, "BPE.matches: false, newPosition.value(" + 260 // newPosition.value + ")" + Debug.getNl() 261 //); 262 return false; 263 } else { 264 265 //Debug.pr(this,"BPE.matches: match= "+match.toString()+Debug.getNl()); 266 matchedAnnots.addAll(match); 267 addedAnnots.addAll(match); 268 newPosition.value = Math.max(newPosition.value, matchEnd); 269 } 270 271 } // for each constraint 272 273 // success: store the annots added this time 274 matchHistory.push(addedAnnots); 275 276 //Debug.pr(this, "BPE.matches: returning true" + Debug.getNl()); 277 // under negation we may not have advanced... 278 if(newPosition.value == position) 279 newPosition.value++; 280 281 return true; 282 } // matches 283 284 /** Create a string representation of the object. */ 285 public String toString() { 286 StringBuffer result = new StringBuffer("{"); 287 Constraint[] constraints = getConstraints(); 288 for(int i = 0; i<constraints.length; i++){ 289 result.append(constraints[i].shortDesc() + ","); 290 } 291 result.setCharAt(result.length() -1, '}'); 292 return result.toString(); 293 } 294 295 /** Create a string representation of the object. */ 296 public String toString(String pad) { 297 String newline = Strings.getNl(); 298 String newPad = Strings.addPadding(pad, INDENT_PADDING); 299 300 StringBuffer buf = new StringBuffer(pad + 301 "BPE: lastFailurePoint(" + lastFailurePoint + "); constraints(" 302 ); 303 304 // constraints 305 if(constraints1 != null) { 306 for(int len = constraints1.size(), i = 0; i < len; i++) 307 buf.append( 308 newline + ((Constraint) constraints1.get(i)).toString(newPad) 309 ); 310 } else { 311 for(int len = constraints2.length, i = 0; i < len; i++) 312 buf.append(newline + constraints2[i].toString(newPad)); 313 } 314 315 // matched annots 316 buf.append( 317 newline + pad + "matchedAnnots: " + matchedAnnots + 318 newline + pad + ") BPE." 319 ); 320 321 return buf.toString(); 322 } // toString 323 324 /** 325 * Returns a short description. 326 */ 327 public String shortDesc() { 328 String res = ""; 329 if(constraints1 != null) { 330 for(int len = constraints1.size(), i = 0; i < len; i++) 331 res += ((Constraint) constraints1.get(i)).toString(); 332 } else { 333 for(int len = constraints2.length, i = 0; i < len; i++) 334 res += constraints2[i].shortDesc(); 335 } 336 return res; 337 } 338 339 public Constraint[] getConstraints(){ 340 return constraints2; 341 } 342 } // class BasicPatternElement 343 344
|
BasicPatternElement |
|