/* ____ ____ ____ ____ ______ *\
** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
** /_____/\____/\___/\____/____/ **
** **
** $Id$
\* */
package scalac.transformer.matching;
import scalac.*;
import scalac.ast.*;
import scalac.symtab.*;
import PatternNode.*;
import Tree.*;
import scalac.transformer.TransMatch.Matcher ;
import scalac.util.Name ;
import scalac.util.Names ;
//import scalac.ast.printer.TextTreePrinter ;
import java.util.Vector ;
import java.util.Iterator ;
/** Matthias' algebraic pattern matcher, with some things factored out
* @author Matthias Zenger, Burak Emir
*/
public class AlgebraicMatcher extends PatternMatcher {
Matcher _m;
/** constructor
*/
public AlgebraicMatcher( Unit unit ) {
super( unit );
this.delegateSequenceMatching = true;
this.optimize = false;
}
/** constructs an algebraic pattern matcher from cases
*/
public void construct( Matcher m, Tree[] cases) {
construct(m, cases, true);
}
/** constructs an algebraic pattern matcher from cases
*/
public void construct( Matcher m, Tree[] cases, boolean doBinding) {
this._m = m;
super.initialize( _m.selector, _m.owner, _m.resultType, doBinding );
for( int i = 0; i < cases.length; i++ ) {
enter( cases[ i ] );//(CaseDef) cases[i], i);
}
if (unit.global.log()) {
unit.global.log("internal pattern matching structure");
print();
}
_m.tree = toTree();
}
/** initializes this AlgebraicMatcher, see Matcher.initialize
void initialize() {
}
*/
/** returns true if p and q are pattern nodes of the same kind and p matches
* whenever q matches, possibly even more often
*/
protected boolean superPat(PatternNode p, PatternNode q) {
switch (p) {
case DefaultPat():
switch (q) {
case DefaultPat():
return true;
//case ConstantPat(_, _):
// return q.type.isSubType(p.type);
}
return false;
case ConstrPat(_):
switch (q) {
case ConstrPat(_):
return q.type.isSubType(p.type);
}
return false;
case ConstantPat( Object pval ):
switch (q) {
case ConstantPat( Object qval ):
return pval.equals(qval);
}
return false;
}
return false;
}
protected boolean isDefaultPat(PatternNode p) {
switch (p) {
case DefaultPat():
return true;
default:
return false;
}
}
boolean isStarApply( Tree.Apply tree ) {
Symbol params[] = tree.fun.type.valueParams();
//System.err.println( tree.fun.type.resultType().symbol() );
return (tree.args.length == 1)
&& (tree.type.symbol().flags & Modifiers.CASE) != 0
&& params.length > 0
&& (params[params.length-1].flags & Modifiers.REPEATED) != 0;
}
//////////// generator methods
public Tree toTree() {
TreeList ts = new TreeList();
ts.append( gen.ValDef(root.symbol(), _m.selector ));
ts.append( gen.ValDef(resultVar,
gen.mkDefaultValue(_m.pos, resultVar.info()) ));
ts.append( gen.If( toTree(root.and),
gen.Ident( _m.pos, resultVar ),
cf.ThrowMatchError( _m.pos, _m.resultType )));
/*
gen.If(
_m.pos,
toTree(root.and),
gen.Ident( _m.pos, resultVar ),
cf.ThrowMatchError( _m.resultType ));
*/
return gen.mkBlock(_m.pos, ts.toArray());
}
protected Tree toTree(PatternNode node, Tree selector) {
//System.err.println("AM.toTree called"+node);
if (node == null)
return gen.mkBooleanLit(_m.pos, false);
switch (node) {
case SeqContainerPat( _, _ ):
return callSequenceMatcher( node,
selector );
default:
return super.toTree( node, selector );
}
}
/** collects all sequence patterns and returns the default
*/
PatternNode collectSeqPats( PatternNode node,
Vector seqPatNodes,
Vector bodies ) {
PatternNode defaultNode = null;
do {
if( node == null )
break;// defaultNode = node;
else
switch( node ) {
case SeqContainerPat( _, _ ):
seqPatNodes.add( node );
bodies.add( toTree( node.and ) );
node = node.or;
break;
default:
defaultNode = node;
}
} while (defaultNode == null) ;
return defaultNode;
}
Tree callSequenceMatcher( PatternNode node,
Tree selector) {
/* ???????????????????????? necessary to test whether is a Seq?
gen.If(selector.pos,
maybe cf.And( cf.Is(selector, seqpat.type())
...
*/
// translate the _.and subtree of this SeqContainerPat
Vector seqPatNodes = new Vector();
Vector bodies = new Vector();
PatternNode defaultNode = collectSeqPats( node,
seqPatNodes,
bodies );
Tree defaultCase = toTree( defaultNode, selector );
SequenceMatcher wordRec = new SequenceMatcher(unit);
Matcher m = new Matcher( _m.owner,
selector,
defs.BOOLEAN_TYPE() );
Tree pats[] = new Tree[ seqPatNodes.size() ];
Tree body[] = new Tree[ seqPatNodes.size() ];
Object tmp[] = bodies.toArray();
int j = 0;
for( Iterator it = seqPatNodes.iterator();
it.hasNext();) {
pats[ j ] = ((SeqContainerPat) it.next()).seqpat;
body[ j ] = (Tree) tmp[j];
j++;
}
//Tree defaultTree = toTree( node.or, selector ); // cdef.body ;
wordRec.construct( m, pats, body, defaultCase, doBinding );
//_m.defs.addAll( m.defs );
return m.tree;
}
}