package scalac.transformer.matching ;
import scalac.*;
import scalac.ast.Tree;
import Tree.*;
//import scala.compiler.printer.TextTreePrinter ; // DEBUGGING\
//import scala.compiler.printer.XMLAutomPrinter ; // DEBUGGING\
import scalac.transformer.TransMatch.Matcher ;
import scalac.ast.* ;
import scalac.symtab.* ;
import java.util.* ;
import ch.epfl.lamp.util.Position;
/** constructs a matcher for a sequence pattern. plays two roles in
* described in design pattern Builder.
* is the "Director" for "Builder" class BerrySethi.
* is the "Builder" for "Director" class TransMatch.
*/
public class SequenceMatcher extends PatternTool {
final static Integer IGNORED = new Integer(42);
CodeFactory cf;
Matcher _m;
//Tree pat[];
//Tree body[];
BindingBerrySethi bbuild = null;
/** translates the det/switching automaton to scala code
* precondition: pat.type() corresponds to element type
*/
Tree addBinderToBody( Tree pat, Tree body ) {
if( bbuild == null )
bbuild = new BindingBerrySethi();
Type elementType = cf.getElemType_Sequence( pat.getType() );
// (a) build *binding* nfa (sequential machine)
NondetWordAutom left = bbuild.automatonFrom( pat, IGNORED );
NondetWordAutom right = bbuild.revnfa;
// (b) determinize + translate L
DetWordAutom dLeft = new DetWordAutom( left );
LeftTracerInScala ltis =
new LeftTracerInScala( dLeft, elementType, _m.owner, _m.selector, cf);
Tree trace = ltis.getTrace();
Tree theTrace = gen.Ident( cf.pos, ltis.resultSym );
// (c) determinize + translate R
DetWordAutom dRight = new DetWordAutom( right, left, dLeft );
Set seqVars = NondetWordAutom.collectVariables( left );
//System.out.println("seqVars here are:"+seqVars);
final RightTracerInScala rtis =
new RightTracerInScala( dRight, seqVars, _m.owner,
cf, pat, elementType );
Tree stms2[] = rtis.getStms( theTrace, unit, body );
// paste statements together
Tree items[] = new Tree[ 1 + stms2.length ];
items[ 0 ] = trace;
System.arraycopy( stms2, 0, items, 1, stms2.length );
return gen.mkBlock( body.pos, items );
}
private NondetWordAutom[] buildNfas( Tree[] pat ) {
BerrySethi build = new BerrySethi();
NondetWordAutom manyNfa[] = new NondetWordAutom[ pat.length ];
for( int i = 0; i < pat.length; i++ ) {
manyNfa[ i ] = build.automatonFrom( pat[ i ],
new Integer( i ));
//manyNfa[ i ].print();
}
return manyNfa;
}
/** constructs a word recognizer from an array of patterns which
* should all be SequencePatterns ( no wildcard * )
* precondition: pat.type corresponds to element type
* @param _m Matcher object, holds the result
* @param pat the (Sequence) patterns
* @param body the bodies
* @param defaultCase code that is run when nothing matches. may be null, it
* becomes a ThrowMatchError then
* @param doBinding flasg that indicates whether variables should be bound
*/
public void construct( Matcher _m,
Tree[] pat,
Tree[] body,
Tree defaultCase,
boolean doBinding ) {
this._m = _m;
//this.pat = pat;
//this.body = body;
assert body.length == pat.length;
if( defaultCase == null )
defaultCase = cf.ThrowMatchError( cf.pos, _m.resultType );
this.cf = new CodeFactory( unit, _m.pos );
Type seqType = pat[ 0 ].getType();
Type elementType = cf.getElemType_Sequence( seqType );
// STEP 1 - build nfas for each pattern
NondetWordAutom manyNfa[] = buildNfas( pat );
// STEP 2 - recognizing
// (a) merge nfas into one if necessary
NondetWordAutom nfa =
(pat.length > 1) ? new NondetWordAutom( manyNfa )
: manyNfa[ 0 ];
//nfa.print();
// (b) determinize
DetWordAutom dfa = new DetWordAutom( nfa );
// (c) translate to scala code
WordAutomInScala scalaAut = new WordAutomInScala( dfa,
elementType,
_m.owner,
cf,
unit.global.target == Global.TARGET_JVM );
scalaAut.translate();
// STEP 3 - binding
Tree newbody[];
if( !doBinding )
newbody = body;
else { // this is done in the body of the matching case
newbody = new Tree[body.length];
for( int i = 0; i < body.length; i++ )
if( !CollectVariableTraverser.containsBinding( pat[ i ] ) )
newbody[ i ] = body[ i ]; // no need for binding
else
newbody[ i ] = addBinderToBody( pat[ i ], body[ i ] );
}
_m.tree = scalaAut.getMatcherSwitch( _m.selector,
defaultCase,
newbody,
_m.resultType );
} // construct (Matcher, Tree[], Tree[], Tree, boolean )
/** constructor, invoked by AlgebraicMatcher
*/
SequenceMatcher( Unit unit ) {
super( unit );
}
} // class SequenceMatcher