/** * $Id$ */ package scalac.transformer.matching ; import scalac.*; import scalac.ast.*; import scalac.symtab.*; import Tree.*; import scalac.transformer.TransMatch.Matcher ; import java.util.* ; import Scope.SymbolIterator; import scalac.ast.printer.TextTreePrinter ; import scalac.util.Name ; import scalac.util.Names ; import ch.epfl.lamp.util.Position; public class RightTracerInScala extends TracerInScala { //Scope scp; //Symbol vars[]; Vector seqVars; Vector allVars; Matcher _m; // Symbol funSym; Symbol elemSym; Symbol targetSym; HashMap helpMap2 ; Vector helpVarDefs; /** translate right tracer to code * @param dfa determinized left tracer * @param left nondeterm. left tracer * @param cf ... * @param pat ? * @param elementType ... */ public RightTracerInScala( DetWordAutom dfa, NondetWordAutom left, Matcher m, CodeFactory cf, Tree pat, Type elementType ) { super( dfa, elementType, m.owner, cf ); this._m = m; Vector seqVars = new Vector(); for( int j = 0; j < left.nstates; j++ ) { if( left.qbinders[ j ] != null ) for( Iterator it = left.qbinders[ j ].iterator(); it.hasNext() ; ) { Symbol varSym = (Symbol) it.next(); if( !seqVars.contains( varSym ) ) seqVars.add( varSym ); } } this.seqVars = seqVars; this.allVars = CollectVariableTraverser.collectVars( pat ); helpMap2 = new HashMap(); helpVarDefs = new Vector(); for( Iterator it = seqVars.iterator(); it.hasNext(); ) { makeHelpVar( (Symbol) it.next() ); } for( Iterator it = allVars.iterator(); it.hasNext(); ) { Symbol varSym = (Symbol) it.next(); if( !seqVars.contains( varSym )) { makeHelpVar( varSym, true ); } } initializeSyms(); } void makeHelpVar( Symbol realVar ) { makeHelpVar( realVar, false ); } /** makes a helpvar and puts mapping into helpMap, ValDef into helpVarDefs */ void makeHelpVar( Symbol realVar, boolean keepType ) { Symbol helpVar = new TermSymbol( pos, cf.fresh.newName( realVar.name .toString() ), owner, 0); //System.out.println("making helpvar : "+realVar+" -> "+helpVar); if( keepType ) helpVar.setType( realVar.type() ); else helpVar.setType( defs.listType(elementType) ); helpMap.put( realVar, helpVar ); Tree rhs; if( keepType ) rhs = gen.mkDefaultValue( cf.pos, realVar.type() ); else rhs = gen.Nil( cf.pos ); helpVar.flags |= Modifiers.MUTABLE; Tree varDef = gen.ValDef( helpVar, rhs ); //((ValDef) varDef).kind = Kinds.VAR; helpVarDefs.add( varDef ); } Tree prependToHelpVar( Symbol realVar, Tree elem ) { Tree hv = refHelpVar( realVar ); return gen.Assign( hv, gen.Cons( cf.pos, elem.type(), elem, hv )); /* return cf.Block(pos, new Tree [] { cf.debugPrintRuntime( "ASSIGN" ), gen.Assign( hv, cf.newSeqCons( elem, hv )) }, defs.UNIT_TYPE); */ } protected void initializeSyms() { this.funSym = newFunSym( "binder" ); this.iterSym = new TermSymbol( pos, cf.fresh.newName("iter"), funSym, 0) .setType( cf.SeqTraceType( elementType )); this.stateSym = new TermSymbol( pos, cf.fresh.newName("q"), funSym, 0 ) .setType( defs.INT_TYPE ) ; this.elemSym = new TermSymbol( pos, cf.fresh.newName("elem"), funSym, 0) .setType( elementType ) ; this.targetSym = new TermSymbol( pos, cf.fresh.newName("trgt"), funSym, 0) .setType( defs.INT_TYPE ) ; funSym.setType( new Type.MethodType( new Symbol[] { iterSym, stateSym }, defs.UNIT_TYPE )); } // same as in LeftTracer Tree code_fail() { return cf.ThrowMatchError( _m.pos, defs.UNIT_TYPE ); } 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 ) else {...}' for( int i = dfa.nstates-1; i >= 0; i-- ) { body = code_state( i, body ); } Tree t3 = gen.If( cf.isEmpty( _iter() ), run_finished( 0 ), gen.mkBlock( new Tree[] { gen.ValDef( targetSym, cf.SeqTrace_headState( gen.Ident( pos, iterSym))), gen.ValDef( elemSym, cf.SeqTrace_headElem( gen.Ident( pos, iterSym))), body })); /* t3 = gen.mkBlock( new Tree[] { cf.debugPrintRuntime("enter binderFun"), cf.debugPrintRuntime(" state:"), cf.debugPrintRuntime( gen.Ident( pos, stateSym )), cf.debugPrintRuntime(" iter:"), cf.debugPrintRuntime(_iter()), cf.debugPrintNewlineRuntime(""), t3 }); */ //System.out.println("enter RightTracerInScala:code_body()");// DEBUG //System.out.println("dfa.nstates"+dfa.nstates);// DEBUG return t3; } /** this one is special, we check the first element of the trace * and choose the next state depending only on the state part */ Tree code_state0( Tree elseBody ) { // careful, map Int to Int HashMap hmap = (HashMap) dfa.deltaq( 0 ); // all the initial states Tree stateBody = code_fail(); // never happens for( Iterator it = hmap.keySet().iterator(); it.hasNext(); ) { Integer targetL = (Integer) it.next(); Integer targetR = (Integer) hmap.get( targetL ); stateBody = gen.If( cf.Equals( gen.Ident( pos, targetSym ), gen.mkIntLit( cf.pos, targetL )), callFun( new Tree[] { cf.SeqTrace_tail( _iter() ), gen.mkIntLit( cf.pos, targetR ) }), stateBody ); } return gen.If( cf.Equals( _state(), gen.mkIntLit( cf.pos, 0 )), stateBody , elseBody ); } Tree code_state( int i, Tree elseBody ) { if( i == 0 ) return code_state0( elseBody ); int finalSwRes; 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 = gen.If( _cur_eq( _iter(), (Label) label ), action, stateBody); } } return gen.If( cf.Equals( _state(), gen.mkIntLit( cf.pos, i )), stateBody , elseBody ); } /** returns a Tree whose type is boolean. * now we care about free vars */ Tree handleBody1( HashMap helpMap3 ) { //System.out.println("Rtis.handleBody ... helpMap = " + helpMap ); // todo: change helpMap s.t. symbols are not reused. Tree res[] = new Tree[ helpMap3.keySet().size() + 1 ]; int j = 0; for( Iterator it = helpMap3.keySet().iterator(); it.hasNext(); ) { Symbol vsym = (Symbol) it.next(); Symbol hv = (Symbol) helpMap3.get( vsym ); hv.setType( defs.listType( elementType ) ) ; Tree refv = gen.Ident(Position.FIRSTPOS, vsym); Tree refhv = gen.Ident(Position.FIRSTPOS, hv); res[ j++ ] = gen.Assign( refhv, refv ); } res[ j ] = gen.mkBooleanLit( Position.FIRSTPOS, true ); // just `true' return gen.mkBlock(res); } // calling the AlgebraicMatcher here Tree _cur_match( Tree pat ) { //System.out.println("RTiS._cur_match("+pat.toString()+")"); //System.out.println("calling algebraic matcher on type:"+pat.type); Matcher m = new Matcher( funSym,//this.funSym, currentElem(), defs.BOOLEAN_TYPE ); // there could be variables in regular expressions under Sequence node, // export those later Vector varsToExport = NoSeqVariableTraverser.varsNoSeq( pat ); HashMap freshenMap = new HashMap(); HashMap helpMap3 = new HashMap(); // "freshening": never use the same symbol more than once // (in later invocations of _cur_match) for( Iterator it = varsToExport.iterator(); it.hasNext(); ) { Symbol key = (Symbol) it.next(); this.helpMap2.put( key, helpMap.get( key )); // "freshening" Symbol newSym = key.cloneSymbol(); newSym.name = key.name.append( Name.fromString("gu234") ); // is fresh now :-) freshenMap.put( key, newSym ); helpMap3.put( newSym, helpMap.get( key )); } //System.out.println("RightTracerInScala::freshenMap :"+freshenMap); //System.out.println("RightTracerInScala:: -pat :"+pat.toString()); //System.out.println("RightTracerInScala::varsToExport :"+varsToExport); // "freshening" TreeCloner st = new TreeCloner(cf.unit.global, freshenMap, Type.IdMap ); pat = st.transform( pat ); //System.out.println("RightTracerInScala:: -pat( after subst ) :"+pat); // val match { case => { ; true } // case _ => false am.construct( m, new CaseDef[] { cf.gen.CaseDef( pat, // if tree val matches pat -> update vars, return true handleBody1( helpMap3 )/* "freshening */), cf.gen.CaseDef( cf.gen.Ident( pat.pos, defs.PATTERN_WILDCARD ), gen.mkBooleanLit( pat.pos, false )) }, // else return false true // do binding please ); return am.toTree(); } /** returns translation of transition with label from i. * returns null if there is no such transition(no translation needed) */ Tree code_delta( int i, Label label ) { HashMap hmap = (HashMap) dfa.deltaq( i ); Integer ntarget = (Integer) hmap.get( label ); Tree algMatchTree = null; if( ntarget == null ) return null; //System.out.println("delta("+i+","+label+")" ); Label theLab = null; switch(label) { case Label.Pair( Integer state, Label lab2 ): //assert ntarget == state; theLab = lab2; switch( lab2 ) { case TreeLabel( Tree pat ): algMatchTree = _cur_match( pat ); break; } break; case DefaultLabel: throw new ApplicationError(); // should not happen } assert dfa.qbinders != null : "qbinders ?"; Vector vars = dfa.qbinders[ i ]; if( vars == null ) vars = new Vector(); // TODO: make this more consistent assert vars != null; //System.out.println("delta: theLab: " + theLab + " vars in current ="+ vars ); if( ntarget == null ) return code_fail(); Tree stms[] = new Tree[ vars.size() + ((algMatchTree != null )? 1 : 0 ) + 1 ]; int j = 0; for( Iterator it = vars.iterator(); it.hasNext(); ) { Symbol var = (Symbol) it.next(); Tree rhs = gen.Ident( pos, elemSym ); stms[ j++ ] = prependToHelpVar( var , rhs); } if( algMatchTree != null ) stms[ j++ ] = algMatchTree ; stms[ j ] = callFun( new Tree[] { cf.SeqTrace_tail( _iter() ), gen.mkIntLit( cf.pos, ntarget ) } ); return gen.mkBlock( pos, stms ); } /* returns statements that do the work of the right-transducer */ Tree[] getStms( Tree trace ) { //System.out.println( "!!getStms.helpVarDefs: "+helpVarDefs); Vector v = new Vector(); for( Iterator it = helpVarDefs.iterator(); it.hasNext(); ) v.add( (Tree) it.next() ); v.add( gen.DefDef( this.funSym, code_body() ) ); v.add( callFun( new Tree[] { trace, gen.mkIntLit( cf.pos, 0 ) } ) ); /* for(Iterator it = helpMap.keySet().iterator(); it.hasNext(); ) { // DEBUG Symbol var = (Symbol)it.next(); v.add( cf.debugPrintRuntime( var.name.toString() )); v.add( cf.debugPrintRuntime( refHelpVar( var )) ); } */ for( Iterator it = seqVars.iterator(); it.hasNext(); ) { v.add( bindVar( (Symbol) it.next() ) ); } Tree result[] = new Tree[ v.size() ]; int j = 0; for( Iterator it = v.iterator(); it.hasNext(); ) { result[ j++ ] = (Tree) it.next(); } // helpvarSEQ via _m.varMap return result; } /** return the accumulator. (same as in LeftTracerInScala) * todo: move tree generation of Unit somewhere else */ Tree run_finished( int state ) { return gen.Block(Position.FIRSTPOS, Tree.EMPTY_ARRAY); } Tree current() { return gen.Ident( pos, targetSym ); } Tree currentElem() { return gen.Ident( pos, elemSym ); } Tree _cur_eq( Tree iter, Label label ) { //System.out.println("_cur_eq, thelab: "+label); switch( label ) { case Pair( Integer target, Label theLab ): return cf.Equals( gen.mkIntLit( cf.pos, target ), current() ); } throw new ApplicationError("expected Pair label"); } }