/*
* ComplexPatternElement.java - transducer class
*
* Copyright (c) 1998-2001, The University of Sheffield.
*
* This file is part of GATE (see http://gate.ac.uk/), and is free
* software, licenced under the GNU Library General Public License,
* Version 2, June 1991 (in the distribution as file licence.html,
* and also available at http://gate.ac.uk/gate/licence.html).
*
* Minor modifications made by Luc Plamondon, Universit� de Montr�al, 27/11/03:
* - migrated original file to the ca.umontreal.iro.rali.gate.jape package.
*
* Hamish Cunningham, 24/07/98
*
* $Id$
*/
package ca.umontreal.iro.rali.gate.jape;
import java.util.*;
import gate.annotation.*;
import gate.util.*;
import gate.*;
/**
* A pattern element enclosed in round brackets. Has a
* ConstraintGroups, Kleene operator and binding name.
*/
public class ComplexPatternElement extends PatternElement
implements JapeConstants, java.io.Serializable
{
/** Debug flag */
private static final boolean DEBUG = false;
/** Kleene operator (defaults to none). Other values: KLEENE_STAR (*);
* KLEENE_PLUS (+); KLEENE_QUERY (?) */
private int kleeneOp = NO_KLEENE_OP;
/** Binding name (may be null). */
private String bindingName = null;
/** Get binding name. */
public String getBindingName() { return bindingName; }
/** Get a list of CPEs that we contain. */
protected Iterator getCPEs() {
return constraintGroup.getCPEs();
} // getCPEs
/** The recursive definition of what pattern elements make up this one. */
private ConstraintGroup constraintGroup;
/** Construction from ConstraintGroup, Kleene operator type and binding
* name. Kleene types are defined in JapeConstants.
*/
public ComplexPatternElement(
ConstraintGroup constraintGroup,
int kleeneOp,
String bindingName
) {
this.constraintGroup = constraintGroup;
this.kleeneOp = kleeneOp;
this.bindingName = bindingName;
}
/** Need cloning for processing of macro references. See comments on
* <CODE>PatternElement.clone()</CODE>
*/
public Object clone() {
ComplexPatternElement newPE = (ComplexPatternElement) super.clone();
newPE.constraintGroup = (ConstraintGroup) constraintGroup.clone();
return newPE;
} // clone
/** Finish: replace dynamic data structures with Java arrays; called
* after parsing.
*/
public void finish() {
constraintGroup.finish();
} // finish
/** Access to the annotations that have been matched. */
public AnnotationSet getMatchedAnnots() {
return constraintGroup.getMatchedAnnots();
}
/** Reset: clear caches of annotations matched. */
public void reset() {
constraintGroup.reset();
super.reset();
} // reset
/** Multilevel rollback of annotation caches. */
public void rollback(int arity) {
/*Debug.pr(
this, "CPE rollback(" + arity + "), mH.size = " +
matchHistory.size() + Debug.getNl()
);*/
// for arity times, pop the arity history stack and
// ask the CG to rollback how ever many times it succeeded then
for(int i=0; i<arity; i++) {
int matchArity = ((Integer) matchHistory.pop()).intValue();
constraintGroup.rollback(matchArity);
}
} // rollback
/** Does this element match the document at this position? */
public boolean matches(
Document doc, int position, MutableInteger newPosition
) {
/*Debug.pr(
this, "CPE.matches: trying at position " + position + Debug.getNl()
);*/
int matchArity = 0; // number of successful applications in this match
boolean firstTry = constraintGroup.matches(doc, position, newPosition);
if(firstTry) {
matchArity++;
/*Debug.pr(this,
"CPE.matches: first try succeeded, newPosition = " + newPosition.value
+ Debug.getNl()
);*/
}
int theEndOfTheDocument = doc.getContent().size().intValue();
if(kleeneOp == NO_KLEENE_OP) {
if(firstTry) matchHistory.push(new Integer(matchArity));
return firstTry;
}
else if(kleeneOp == KLEENE_QUERY) {
if(firstTry) matchHistory.push(new Integer(matchArity));
/* Debug.pr(this, "CPE.matches: true, QUERY rule"); */
return true;
}
else if(kleeneOp == KLEENE_PLUS) {
if(! firstTry)
return false; // no cache purge: maybe we're under another * etc.
}
else if(kleeneOp == KLEENE_STAR && !firstTry) {
/*Debug.pr(this,
"CPE.matches: true, STAR rule, newPos("+newPosition.value+")");*/
matchHistory.push(new Integer(matchArity));
return true;
}
// we get here if we have either Kleene *, or Kleene +, and a
// successful first move. now we try it again as many times as it
// succeeds, store the final match arity and then return true
while(constraintGroup.matches(doc, newPosition.value, newPosition)) {
/*Debug.pr(this,
"CPE.matches: trying while loop, matchArity = " + matchArity);*/
matchArity++;
// if we've negated failing constraints, we may match for ever
if(newPosition.value >= theEndOfTheDocument) // stop at the end!
break;
} // while
matchHistory.push(new Integer(matchArity));
//Debug.pr(this,
// "CPE.matches: true, matchArity(" + matchArity + ") pushed");
return true;
} // matches
/** Create a string representation of the object. */
public String toString() { return toString(""); }
/** Create a string representation of the object. */
public String toString(String pad) {
String newline = Strings.getNl();
StringBuffer buf = new StringBuffer(
pad + "CPE: bindingName(" + bindingName + "); kleeneOp("
);
switch(kleeneOp) {
case NO_KLEENE_OP: buf.append("NO_KLEENE_OP"); break;
case KLEENE_STAR: buf.append("KLEENE_STAR"); break;
case KLEENE_QUERY: buf.append("KLEENE_QUERY"); break;
case KLEENE_PLUS: buf.append("KLEENE_PLUS"); break;
default: break;
}
buf.append(
"); constraintGroup(" + newline +
constraintGroup.toString(Strings.addPadding(pad, INDENT_PADDING)) +
newline + pad + ") CPE." + newline
);
return buf.toString();
} // toString
//needed by FSM
public int getKleeneOp(){ return kleeneOp; };
public ConstraintGroup getConstraintGroup(){ return constraintGroup; };
} // class ComplexPatternElement