1   /*
2    *  ComplexPatternElement.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: ComplexPatternElement.java,v 1.8 2001/09/13 12:09:49 kalina 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 enclosed in round brackets. Has a
27    * ConstraintGroups, Kleene operator and binding name.
28    */
29  public class ComplexPatternElement extends PatternElement
30  implements JapeConstants, java.io.Serializable
31  {
32    /** Debug flag */
33    private static final boolean DEBUG = false;
34  
35    /** Kleene operator (defaults to none). Other values: KLEENE_STAR (*);
36      * KLEENE_PLUS (+); KLEENE_QUERY (?) */
37    private int kleeneOp = NO_KLEENE_OP;
38  
39    /** Binding name (may be null). */
40    private String bindingName = null;
41  
42    /** Get binding name. */
43    public String getBindingName() { return bindingName; }
44  
45    /** Get a list of CPEs that we contain. */
46    protected Iterator getCPEs() {
47      return constraintGroup.getCPEs();
48    } // getCPEs
49  
50    /** The recursive definition of what pattern elements make up this one. */
51    private ConstraintGroup constraintGroup;
52  
53    /** Construction from ConstraintGroup, Kleene operator type and binding
54      * name. Kleene types are defined in JapeConstants.
55      */
56    public ComplexPatternElement(
57      ConstraintGroup constraintGroup,
58      int kleeneOp,
59      String bindingName
60    ) {
61      this.constraintGroup = constraintGroup;
62      this.kleeneOp = kleeneOp;
63      this.bindingName = bindingName;
64    }
65  
66    /** Need cloning for processing of macro references. See comments on
67      * <CODE>PatternElement.clone()</CODE>
68      */
69    public Object clone() {
70      ComplexPatternElement newPE = (ComplexPatternElement) super.clone();
71      newPE.constraintGroup = (ConstraintGroup) constraintGroup.clone();
72      return newPE;
73    } // clone
74  
75    /** Finish: replace dynamic data structures with Java arrays; called
76      * after parsing.
77      */
78    public void finish() {
79      constraintGroup.finish();
80    } // finish
81  
82    /** Access to the annotations that have been matched. */
83    public AnnotationSet getMatchedAnnots() {
84      return constraintGroup.getMatchedAnnots();
85    }
86  
87    /** Reset: clear caches of annotations matched. */
88    public void reset() {
89      constraintGroup.reset();
90      super.reset();
91    } // reset
92  
93    /** Multilevel rollback of annotation caches. */
94    public void rollback(int arity) {
95      /*Debug.pr(
96        this, "CPE rollback(" + arity + "), mH.size = " +
97        matchHistory.size() + Debug.getNl()
98      );*/
99  
100     // for arity times, pop the arity history stack and
101     // ask the CG to rollback how ever many times it succeeded then
102     for(int i=0; i<arity; i++) {
103       int matchArity = ((Integer) matchHistory.pop()).intValue();
104       constraintGroup.rollback(matchArity);
105     }
106   } // rollback
107 
108   /** Does this element match the document at this position? */
109   public boolean matches(
110     Document doc, int position, MutableInteger newPosition
111   ) {
112     /*Debug.pr(
113       this, "CPE.matches: trying at position " + position + Debug.getNl()
114     );*/
115     int matchArity = 0; // number of successful applications in this match
116     boolean firstTry = constraintGroup.matches(doc, position, newPosition);
117     if(firstTry) {
118       matchArity++;
119       /*Debug.pr(this,
120         "CPE.matches: first try succeeded, newPosition = " + newPosition.value
121         + Debug.getNl()
122       );*/
123     }
124     int theEndOfTheDocument = doc.getContent().size().intValue();
125 
126     if(kleeneOp == NO_KLEENE_OP) {
127       if(firstTry) matchHistory.push(new Integer(matchArity));
128       return firstTry;
129     }
130     else if(kleeneOp == KLEENE_QUERY) {
131       if(firstTry) matchHistory.push(new Integer(matchArity));
132       /* Debug.pr(this, "CPE.matches: true, QUERY rule"); */
133       return true;
134     }
135     else if(kleeneOp == KLEENE_PLUS) {
136       if(! firstTry)
137         return false; // no cache purge: maybe we're under another * etc.
138     }
139     else if(kleeneOp == KLEENE_STAR && !firstTry) {
140       /*Debug.pr(this,
141         "CPE.matches: true, STAR rule, newPos("+newPosition.value+")");*/
142       matchHistory.push(new Integer(matchArity));
143       return true;
144     }
145 
146     // we get here if we have either Kleene *, or Kleene +, and a
147     // successful first move. now we try it again as many times as it
148     // succeeds, store the final match arity and then return true
149     while(constraintGroup.matches(doc, newPosition.value, newPosition)) {
150       /*Debug.pr(this,
151         "CPE.matches: trying while loop, matchArity = " + matchArity);*/
152       matchArity++;
153 
154       // if we've negated failing constraints, we may match for ever
155       if(newPosition.value >= theEndOfTheDocument) // stop at the end!
156         break;
157     } // while
158     matchHistory.push(new Integer(matchArity));
159     //Debug.pr(this,
160     //         "CPE.matches: true, matchArity(" + matchArity + ") pushed");
161     return true;
162   } // matches
163 
164 
165   /** Create a string representation of the object. */
166   public String toString() { return toString(""); }
167 
168   /** Create a string representation of the object. */
169   public String toString(String pad) {
170     String newline = Strings.getNl();
171 
172     StringBuffer buf = new StringBuffer(
173       pad + "CPE: bindingName(" + bindingName + "); kleeneOp("
174     );
175 
176     switch(kleeneOp) {
177       case NO_KLEENE_OP: buf.append("NO_KLEENE_OP"); break;
178       case KLEENE_STAR:  buf.append("KLEENE_STAR");  break;
179       case KLEENE_QUERY: buf.append("KLEENE_QUERY"); break;
180       case KLEENE_PLUS:  buf.append("KLEENE_PLUS");  break;
181       default: break;
182     }
183 
184     buf.append(
185       "); constraintGroup(" + newline +
186       constraintGroup.toString(Strings.addPadding(pad, INDENT_PADDING)) +
187       newline + pad + ") CPE." + newline
188     );
189 
190     return buf.toString();
191   } // toString
192   //needed by FSM
193 
194   public int getKleeneOp(){ return kleeneOp; };
195 
196   public ConstraintGroup getConstraintGroup(){ return constraintGroup; };
197 
198 } // class ComplexPatternElement
199 
200 
201 // $Log: ComplexPatternElement.java,v $
202 // Revision 1.8  2001/09/13 12:09:49  kalina
203 // Removed completely the use of jgl.objectspace.Array and such.
204 // Instead all sources now use the new Collections, typically ArrayList.
205 // I ran the tests and I ran some documents and compared with keys.
206 // JAPE seems to work well (that's where it all was). If there are problems
207 // maybe look at those new structures first.
208 //
209 // Revision 1.7  2001/09/12 11:59:33  kalina
210 // Changed the old JAPE stuff to use the new Collections API,
211 // instead of com.objectspace stuff. Will eliminate that library
212 // completely very soon! Just one class left to re-implement,
213 //
214 // ParseCPSL.jj changed accordingly. All tested and no smoke.
215 //
216 // Revision 1.6  2000/11/08 16:35:02  hamish
217 // formatting
218 //
219 // Revision 1.5  2000/10/26 10:45:30  oana
220 // Modified in the code style
221 //
222 // Revision 1.4  2000/10/16 16:44:33  oana
223 // Changed the comment of DEBUG variable
224 //
225 // Revision 1.3  2000/10/10 15:36:35  oana
226 // Changed System.out in Out and System.err in Err;
227 // Added the DEBUG variable seted on false;
228 // Added in the header the licence;
229 //
230 // Revision 1.2  2000/04/14 18:02:46  valyt
231 // Added some gate.fsm classes
232 // added some accessor function in old jape classes
233 //
234 // Revision 1.1  2000/02/23 13:46:05  hamish
235 // added
236 //
237 // Revision 1.1.1.1  1999/02/03 16:23:01  hamish
238 // added gate2
239 //
240 // Revision 1.14  1998/11/13 13:17:16  hamish
241 // merged in the doc length bug fix
242 //
243 // Revision 1.13  1998/11/12 17:47:27  kalina
244 // A bug fixed, wasn't restoring the document length
245 //
246 // Revision 1.12  1998/11/05 13:36:29  kalina
247 // moved to use array of JdmAttributes for selectNextAnnotation instead
248 // of a sequence
249 //
250 // Revision 1.11  1998/11/01 21:21:35  hamish
251 // use Java arrays in transduction where possible
252 //
253 // Revision 1.10  1998/10/06 16:16:09  hamish
254 // negation percolation during constrain add; position advance when none at end
255 //
256 // Revision 1.9  1998/10/01 16:06:29  hamish
257 // new appelt transduction style, replacing buggy version
258 //
259 // Revision 1.8  1998/09/26 09:19:14  hamish
260 // added cloning of PE macros
261 //
262 // Revision 1.7  1998/09/17 16:48:29  hamish
263 // added macro defs and macro refs on LHS
264 //
265 // Revision 1.6  1998/08/12 15:39:32  hamish
266 // added padding toString methods
267 //
268 // Revision 1.5  1998/08/05 21:58:04  hamish
269 // backend works on simple test
270 //
271 // Revision 1.4  1998/08/03 19:51:19  hamish
272 // rollback added
273 //
274 // Revision 1.3  1998/07/30 11:05:14  hamish
275 // more jape
276 //
277 // Revision 1.2  1998/07/29 11:06:54  hamish
278 // first compiling version
279 //
280 // Revision 1.1.1.1  1998/07/28 16:37:46  hamish
281 // gate2 lives
282