| 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 |