package scalac.transformer.matching ;
import scalac.* ;
import scalac.typechecker.* ;
import scalac.symtab.Symbol ;
import scalac.symtab.Type ;
import scalac.symtab.TermSymbol ;
import scalac.symtab.Definitions ;
import scalac.ast.Tree;
import scalac.ast.TreeGen;
import scalac.util.Name;
import scalac.util.Names;
import Tree.*;
import scalac.transformer.TransMatch.Matcher ;
import java.util.* ;
import ch.epfl.lamp.util.Position;
public class Autom2Scala {
static final Name HASNEXT = Name.fromString("hasnext");
static final Name CURRENT_ELEM = Name.fromString("cur");
final int FAIL = -1;
DetWordAutom dfa;
protected CodeFactory cf;
Vector freeVars;
Vector mdefs;
//Tree matcherDef;
//Tree matcherSwitch;
Definitions defs;
TreeGen gen;
/** owner of the pattern matching expression
*/
protected Symbol owner;
/** symbol of the matcher fun
*/
Symbol funSym;
/** symbol of the iterator ( scala.SequenceIterator )
*/
Symbol iterSym;
/** symbol of the switching result ( scala.Int )
*/
Symbol resultSym;
/** symbol of the state variable ( scala.Int )
*/
Symbol stateSym;
protected Type elementType;
public int pos;
String funSymName;
Symbol newFunSym( String prefix ) {
return new TermSymbol( /*Kinds.FUN, */
pos,
cf.fresh.newName( prefix ),
owner,
0);
}
Symbol newParam( String prefix ) {
return new TermSymbol( /*Kinds.VAL, */
pos,
cf.fresh.newName( prefix ),
funSym,
0);
}
Type funRetType() {
switch( funSym.type() ) {
case MethodType( _, Type retType ):
return retType;
}
throw new RuntimeException();
}
Tree callFun( Tree[] args ) {
return gen.Apply( pos,
gen.Ident( pos, funSym ),
args).setType( funRetType() );
}
/** init funSym, iterSym, stateSym, resultSym + allocate mdefs.
* a subclass overriding initializeSyms may change these
* (esp. funSym)
*/
protected void initializeSyms() {
if( funSymName == null )
funSymName = "matcher";
// the function that does the matching
this.funSym = newFunSym( funSymName );
this.iterSym = newParam("iter")
.setType( cf._seqIterType( elementType ) ) ;
this.stateSym = newParam("q")
.setType( defs.INT_TYPE ) ;
this.resultSym = new TermSymbol( /*Kinds.VAR,*/
pos,
cf.fresh.newName("swRes"),
owner,
0 )
.setType( defs.INT_TYPE ) ;
this.funSym
.setType( new Type.MethodType( new Symbol[] {
iterSym, stateSym }, defs.INT_TYPE ));
this.curSym = new TermSymbol( /*Kinds.VAL, */
pos,
CURRENT_ELEM,
funSym,//clazzOwner,
0)
.setType( elementType );
this.hasnSym = new TermSymbol( /*Kinds.VAL, */
pos,
HASNEXT,
funSym,//clazzOwner,
0)
.setType( defs.BOOLEAN_TYPE );
}
public Autom2Scala( DetWordAutom dfa,
Type elementType,
Symbol owner,
CodeFactory cf ) {
this.dfa = dfa;
this.elementType = elementType;
this.defs = cf.defs;
this.gen = cf.gen;
this.owner = owner;
this.pos = Position.FIRSTPOS;
this.cf = cf;
this.am = new AlgebraicMatcher( cf.unit, cf.infer );
this.mdefs = new Vector();
this.freeVars = new Vector();
}
public Tree theDefDef;
Symbol curSym;
Symbol hasnSym;
// overridden in TracerInScala
Tree loadCurrentElem( Tree body ) {
return cf.Block( Position.FIRSTPOS, new Tree[] {
cf.gen.ValDef( Position.FIRSTPOS,
this.hasnSym,
cf._hasNext( _iter() ) ),
cf.gen.ValDef( Position.FIRSTPOS,
this.curSym,
cf.If( _ref( hasnSym ),//cf._hasNext( _iter() ),
cf._next( _iter() ),
cf.ignoreValue( curSym.type() ))),
body },
body.type() );
}
Tree currentElem() {
return gen.Ident(Position.FIRSTPOS, curSym);
}
Tree currentMatches( Label label ) {
return _cur_eq( _iter(), label );
}
//
// translation of automata to scala code
//
/** creates an int variable
*/
Tree _intvar( Symbol sym, Tree init ) {
return gen.ValDef( pos, sym, init );
/*
Kinds.VAR,
0,
sym.name,
gen.mkType(pos, defs.INT_TYPE),
init)
.setType( defs.UNIT_TYPE )
.symbol( sym );*/
}
/** `<sym> = val'
Tree code_assignInt( Symbol sym, Integer val ){
return make.Assign(pos,
code_ref( sym ),
gen.mkIntLit(Position.FIRSTPOS, val ))
.setType( defs.UNIT_TYPE );
}
*/
// the caller needs to set the type !
Tree _applyNone( Tree arg ) {
return cf.make.Apply(pos, arg, Tree.EMPTY_ARRAY/*None*/ );
}
Tree _scala() {
// return gen.mkId( defs.SCALA ) // try this
return gen.Ident(pos, defs.SCALA ); /*make.Ident( pos,
SCALA_N )
.setType( defs.SCALA.type() ).symbol( defs.SCALA );*/
}
/** `<switchResult>'
*/
public Tree _swres() { return gen.Ident( pos, resultSym );}
/** `<state>'
*/
public Tree _state() { return gen.Ident( pos, stateSym ); }
/** code to reference the iterator
*/
Tree _iter() { return gen.Ident( pos, iterSym ); }
/** body of the matcherDefFun
*/
public Tree code_body() {
Tree body = code_fail(); // never reached at runtime.
// state [ nstates-1 ] is the dead state, so we skip it
//`if( state == q ) <code_state> else {...}'
for( int i = dfa.nstates-2; i >= 0; i-- ) {
body = code_state( i, body );
}
return loadCurrentElem( body );
}
Tree _cur_eq( Tree iter, Label label ) {
switch( label ) {
case TreeLabel( Tree pat ):
return _cur_match( pat );
case SimpleLabel( Tree.Literal lit ):
return cf.Equals( currentElem(), lit );
}
throw new ApplicationError("expected either algebraic or simple label:"+label);
}
AlgebraicMatcher am;
void handleVars( ) {
}
// returns a Tree whose type is boolean.
Tree handleBody( Object help ) {
// don't care about free vars
return gen.mkBooleanLit( Position.FIRSTPOS, true );
}
// calling the /*AlgebraicMatcher*/PatternMatcher here
Tree _cur_match( Tree pat ) {
//System.out.println("calling algebraic matcher on type:"+pat.type);
Matcher m = new Matcher( funSym,//this.funSym,
currentElem(),
defs.BOOLEAN_TYPE );
am.construct( m, new CaseDef[] {
(CaseDef) cf.make.CaseDef( pat.pos,
pat,
Tree.Empty,
handleBody( freeVars )),
(CaseDef) cf.make.CaseDef( pat.pos,
cf.make.Ident(pat.pos, Names.WILDCARD)
//.setSymbol( Symbol.NONE )
.setType(pat.type()),
Tree.Empty,
gen.mkBooleanLit( pat.pos, false )) },
false
);
Tree res = am.toTree().setType( defs.BOOLEAN_TYPE );
return res;
}
Tree code_delta( int i, Label label ) {
throw new RuntimeException();
}
Tree code_fail() {
return gen.mkIntLit(Position.FIRSTPOS, FAIL );
}
/** code for the return value of the automaton translation
*/
Tree run_finished( int state ) {
if( dfa.isFinal( state )) {
return gen.mkIntLit(Position.FIRSTPOS, ((Integer) dfa.finals.get( new Integer( state ) )).intValue() );
}
return gen.mkIntLit(Position.FIRSTPOS, FAIL );
}
/*
Tree ifInputHasNext() {
return cf.If( cf._hasNext( _iter() ),
cf.Block( stateBody.pos,
new Tree[] {
loadCurrentElem(),
stateBody},
stateBody.type()) );
}
*/
Tree wrapStateBody0( Tree stateBody,
Tree elseBody,
int i ) {
return cf.If( cf.Equals( _state(), gen.mkIntLit(Position.FIRSTPOS, i )),
stateBody ,
elseBody );
}
// `val cur := iter.next()'
Tree wrapStateBody( Tree stateBody,
Tree elseBody,
Tree runFinished, int i ) {
stateBody = cf.If( cf.Negate( _ref( hasnSym )),//cf._not_hasNext( _iter() ),
runFinished,
stateBody);/*
cf.Block( stateBody.pos,
new Tree[] {
loadCurrentElem(),
stateBody},
stateBody.type()) );*/
return wrapStateBody0( stateBody , elseBody, i );
}
/** return code for state i of the dfa
*/
Tree code_state( int i, Tree elseBody ) {
Tree runFinished; // holds result of the run
int finalSwRes;
runFinished = run_finished( i );
if( dfa.isSink( i ) ) // state won't change anymore (binding?)
return cf.If( cf.Equals( _state(), gen.mkIntLit(Position.FIRSTPOS, i )),
runFinished,
elseBody );
Tree stateBody ; // action(delta) for one particular label/test
// default action (fail if there is none)
stateBody = code_delta( i, Label.DefaultLabel);
/*
if( stateBody == null )
stateBody = code_fail();
*/
// transitions of state i
HashMap trans = ((HashMap[])dfa.deltaq)[ i ];
for( Iterator labs = dfa.labels.iterator(); labs.hasNext() ; ) {
Object label = labs.next();
Integer next = (Integer) trans.get( label );
Tree action = code_delta( i, (Label) label );
if( action != null ) {
stateBody = cf.If( currentMatches((Label) label ),
action,
stateBody);
}
}
return wrapStateBody( stateBody,
elseBody,
runFinished,
i );
}
/** code to reference a variable
*/
Tree _ref( Symbol sym ) {
return gen.Ident( pos, sym );
}
}