summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sources/scala/tools/scalac/transformer/matching/AlgebraicMatcher.scala190
-rw-r--r--sources/scala/tools/scalac/transformer/matching/Autom2Scala.scala221
-rw-r--r--sources/scala/tools/scalac/transformer/matching/LeftTracerInScala.scala242
-rw-r--r--sources/scala/tools/scalac/transformer/matching/RightTracerInScala.scala502
-rw-r--r--sources/scala/tools/scalac/transformer/matching/SequenceMatcher.scala174
-rw-r--r--sources/scala/tools/scalac/transformer/matching/TracerInScala.scala27
-rw-r--r--sources/scala/tools/scalac/transformer/matching/WordAutomInScala.scala176
7 files changed, 1532 insertions, 0 deletions
diff --git a/sources/scala/tools/scalac/transformer/matching/AlgebraicMatcher.scala b/sources/scala/tools/scalac/transformer/matching/AlgebraicMatcher.scala
new file mode 100644
index 0000000000..5fdfc7e94f
--- /dev/null
+++ b/sources/scala/tools/scalac/transformer/matching/AlgebraicMatcher.scala
@@ -0,0 +1,190 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+\* */
+
+// $Id$
+
+import java.io._;
+import java.util._;
+import scalac.{Global => scalac_Global};
+import scalac._;
+import scalac.ast._;
+import scalac.symtab._;
+import scalac.util._; // Names
+
+import scala.tools.scalac.util.NewArray;
+import scalac.transformer.{ OwnerTransformer => scalac_transformer_OwnerTransformer };
+
+import scalac.transformer.matching.PartialMatcher ;
+import scalac.transformer.matching.PatternMatcher ;
+
+import scalac.transformer.matching.PatternNode ;
+//import scalac.transformer.matching.SequenceMatcher ;
+import PatternNode._ ;
+
+package scala.tools.scalac.transformer.matching {
+
+ /** Matthias' algebraic pattern matcher, with some things factored out,
+ * then translated to scala
+ * @author Matthias Zenger, Burak Emir
+ */
+ class AlgebraicMatcher(unit: CompilationUnit) extends PatternMatcher(unit) {
+
+/*
+import scalac.*;
+import scalac.ast.*;
+import scalac.atree.AConstant;
+import scalac.symtab.*;
+
+import Tree.*;
+
+import scalac.util.Name ;
+import scalac.util.Names ;
+
+import java.util.Vector ;
+import java.util.Iterator ;
+*/
+
+ var _m:PartialMatcher = _;
+
+ this.delegateSequenceMatching = true;
+ this.optimize = false;
+
+ /** constructs an algebraic pattern matcher from cases
+ */
+ def construct(m: PartialMatcher, cases:Array[Tree]): Unit = {
+ construct(m, cases, true);
+ }
+
+ /** constructs an algebraic pattern matcher from cases
+ */
+ def construct(m: PartialMatcher, cases: Array[Tree], doBinding: Boolean): Unit = {
+ this._m = m;
+ super.initialize( _m.selector, _m.owner, _m.resultType, doBinding );
+ var i = 0; while (i < cases.length) {
+ enter( cases( i ) ); //(CaseDef) cases[i], i);
+ i = i + 1;
+ }
+ if (unit.global.log()) {
+ unit.global.log("internal pattern matching structure");
+ print();
+ }
+ _m.tree = toTree();
+ }
+
+
+ /** initializes this AlgebraicMatcher, see Matcher.initialize
+ void initialize() {}
+ */
+
+ def isStarApply(tree: Tree.Apply): Boolean = {
+ val params:Array[Symbol] = tree.fun.getType().valueParams();
+ //System.err.println( tree.fun.type.resultType().symbol() );
+ (tree.args.length == 1)
+ && (tree.getType().symbol().flags & Modifiers.CASE) != 0
+ && params.length > 0
+ && (params(params.length-1).flags & Modifiers.REPEATED) != 0;
+ }
+
+//////////// generator methods
+
+ override def toTree(): Tree = {
+ val ts = NewArray.Tree (
+ gen.ValDef(root.symbol(), _m.selector ),
+ gen.ValDef(resultVar,
+ gen.mkDefaultValue(_m.pos, resultVar.info()) ));
+ val res = gen.If( super.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 ));
+ */
+ gen.mkBlock(_m.pos, ts, res);
+ }
+
+ protected override def toTree(node: PatternNode, selector: Tree): Tree = {
+ //System.err.println("AM.toTree called"+node);
+ if (node == null)
+ gen.mkBooleanLit(_m.pos, false);
+ else node.match {
+ case SeqContainerPat( _, _ ) =>
+ callSequenceMatcher( node,
+ selector );
+ case _ =>
+ super.toTree( node, selector );
+ }
+ }
+
+ /** collects all sequence patterns and returns the default
+ */
+ def collectSeqPats(node1: PatternNode, seqPatNodes: Vector, bodies: Vector ): PatternNode = {
+ var node = node1;
+ var defaultNode: PatternNode = null;
+ var exit = false;
+ do {
+ if( node == null )
+ exit=true;//defaultNode = node; // break
+ else
+ node.match {
+ case SeqContainerPat( _, _ ) =>
+ seqPatNodes.add( node );
+ bodies.add( super.toTree( node.and ) );
+ node = node.or;
+ exit//defaultNode = node; // break;
+
+ case _ =>
+ defaultNode = node;
+ }
+ } while (!exit && (null == defaultNode)) ;
+
+ defaultNode;
+ }
+
+ def callSequenceMatcher(node: PatternNode, selector: Tree): Tree = {
+
+ /* ???????????????????????? 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
+
+ val seqPatNodes = new Vector();
+ val bodies = new Vector();
+
+ var defaultNode = collectSeqPats( node, seqPatNodes, bodies );
+
+ val defaultCase = toTree( defaultNode, selector );
+
+ val wordRec = new SequenceMatcher(unit);
+
+ val m = new PartialMatcher( _m.owner, selector, defs.boolean_TYPE() );
+
+ val pats = new Array[Tree]( seqPatNodes.size() );
+ val body = new Array[Tree]( seqPatNodes.size() );
+
+ val tmp = bodies.toArray();
+ var j = 0;
+ val it = seqPatNodes.iterator();
+ while(it.hasNext()) {
+ pats( j ) = it.next().asInstanceOf[SeqContainerPat].seqpat;
+ body( j ) = tmp(j).asInstanceOf[Tree];
+ j = j + 1;
+ }
+ //Tree defaultTree = toTree( node.or, selector ); // cdef.body ;
+
+ wordRec.construct( m, pats, body, defaultCase, doBinding );
+
+ //_m.defs.addAll( m.defs );
+
+ m.tree;
+ }
+
+ }
+
+}
diff --git a/sources/scala/tools/scalac/transformer/matching/Autom2Scala.scala b/sources/scala/tools/scalac/transformer/matching/Autom2Scala.scala
new file mode 100644
index 0000000000..dc45f5b841
--- /dev/null
+++ b/sources/scala/tools/scalac/transformer/matching/Autom2Scala.scala
@@ -0,0 +1,221 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+\* */
+
+// $Id$
+
+import scalac.{Global => scalac_Global};
+import scalac._;
+import scalac.ast._;
+import scalac.symtab._;
+import scalac.util._; // Names
+
+import scala.tools.scalac.util.NewArray;
+import scalac.transformer.{ OwnerTransformer => scalac_transformer_OwnerTransformer };
+
+import scalac.transformer.matching.PartialMatcher ;
+import scalac.transformer.matching.PatternMatcher ;
+
+import scalac.transformer.matching.CodeFactory ;
+import scalac.transformer.matching.DetWordAutom ;
+import scalac.transformer.matching.PatternNode ;
+import scalac.transformer.matching.Label ;
+//import scalac.transformer.matching.SequenceMatcher ;
+import PatternNode._ ;
+import Label._ ;
+
+
+
+import Tree._;
+
+import java.util._ ;
+
+import scala.tools.util.Position;
+
+package scala.tools.scalac.transformer.matching {
+
+ /** @param owner owner of the pattern matching expression
+ */
+ class Autom2Scala(val dfa: DetWordAutom, val elementType: Type, val owner: Symbol, val cf: CodeFactory) {
+
+ protected var optimize = true;
+
+ final val FAIL = -1;
+
+ /** symbol of the matcher DefDef or Label */
+ var funSym:Symbol = _;
+
+ /** symbol of the iterator ( scala.SequenceIterator ) */
+ var iterSym: Symbol = _;
+
+ /** symbol of the switching result ( scala.Int ) */
+ var resultSym: Symbol = _;
+
+ /** symbol of the state variable ( scala.Int ) */
+ var stateSym: Symbol = _;
+
+ /** symbol of variable holding current label */
+ var curSym: Symbol = _;
+
+ /** symbol of boolean variable that indicates we have not reached end of sequence */
+ var hasnSym: Symbol = _;
+
+ val am = new AlgebraicMatcher( cf.unit );
+
+ var pos: Int = Position.FIRSTPOS;
+
+ def funRetType(): Type = {
+ funSym.getType().match {
+ case Type.MethodType( _, retType )=>
+ retType;
+ case _ => throw new RuntimeException();
+ }
+ }
+ final def gen = cf.gen;
+
+ def callFun(args: Array[Tree]): Tree = {
+ gen.mkApply_V(gen.Ident(pos, funSym), args);
+ }
+
+ // overridden in RightTracerInScala
+ def loadCurrentElem(body: Tree): Tree = {
+ gen.mkBlock( NewArray.Tree (
+ cf.gen.ValDef(this.hasnSym,
+ cf._hasNext( _iter() ) ),
+ cf.gen.ValDef(this.curSym,
+ gen.If(gen.Ident( pos, hasnSym ),
+ cf._next( _iter() ),
+ gen.mkDefaultValue(cf.pos,curSym.getType())))
+ ),
+ body );
+ }
+
+ /** bug ?? */
+ def currentElem() = { gen.Ident( cf.pos, curSym ).setType( curSym.getType() ); }
+
+ def currentMatches(label: Label): Tree = {
+ label.match {
+ case TreeLabel( pat ) =>
+ _cur_match( pat );
+ case SimpleLabel(lit: Tree.Literal) =>
+ cf.Equals( currentElem(), lit );
+ case _ => // cannot happen
+ throw new ApplicationError("expected either algebraic or simple label:"+label);
+ }
+ }
+
+ //
+ // translation of automata to scala code
+ //
+
+
+ /** `[switchResult]' */
+ def _swres(): Tree = { gen.Ident( pos, resultSym );}
+
+ /** `<state>' param */
+ def _state(): Tree = { gen.Ident( pos, stateSym ); }
+
+ /** `<iterator>' param */
+ def _iter(): Tree = { gen.Ident( pos, iterSym ); }
+
+ /** simple optimization: if we are in a sink state, stop traversing sequence
+ */
+ def stateWrap(i: Int): Tree = {
+ if( dfa.isSink( i ))
+ run_finished( i ); // state won't change! optimization
+ else
+ gen.If( cf.Negate( gen.Ident( pos, hasnSym )),
+ run_finished( i ),
+ code_state_NEW( i ));
+ }
+
+ /** body of the matcherDefFun
+ */
+ def code_body_NEW(): Tree = {
+ val tags = new Array[Int](dfa.nstates());
+ val bodies = new Array[Tree](dfa.nstates());
+ var i = 0; while (i < dfa.nstates()) {
+ tags( i ) = i;
+ bodies( i ) = stateWrap( i );
+ i = i + 1;
+ }
+ //if( optimize )
+ loadCurrentElem( gen.Switch( _state(),
+ tags,
+ bodies,
+ code_error(), // cannot happen
+ funRetType()));
+ /*
+ Tree res = code_error();
+ for( int i = dfa.nstates-2; i>= 0; i-- )
+ res = gen.If( cf.Equals( _state(), gen.mkIntLit( cf.pos, i )),
+ bodies[ i ] ,
+ res );
+
+ return loadCurrentElem( res );
+ */
+ }
+
+ /* calling the (AlgebraicMatcher)PatternMatcher here */
+ def _cur_match(pat: Tree): Tree = {
+ val m = new PartialMatcher( this.funSym, /* owner*/
+ currentElem(), /* root */
+ cf.defs.boolean_TYPE() /* restype */);
+
+ am.construct( m, Predef.Array[Tree] (
+ cf.gen.CaseDef( pat,
+ gen.mkBooleanLit( pat.pos, true )),
+ cf.gen.CaseDef( cf.gen.Ident(pat.pos, cf.defs.PATTERN_WILDCARD),
+ gen.mkBooleanLit( pat.pos, false )) ),
+ false);
+ am.toTree();
+ }
+
+ // @todo should be abstract
+ def code_delta( i:Int, label: Label): Tree = {
+ throw new RuntimeException();
+ }
+
+ /** some error happened which is due to bug in translation/automaton
+ */
+ final def code_error(): Tree = {
+ cf.ThrowMatchError( pos, funRetType() );
+ }
+
+ def code_fail(): Tree = {
+ gen.mkIntLit(Position.FIRSTPOS, FAIL );
+ }
+
+ /** code for the return value of the automaton translation
+ */
+ def run_finished(state: Int): Tree = {
+ if( dfa.isFinal( state ))
+ gen.mkIntLit(Position.FIRSTPOS, dfa.finals.get( new Integer( state ) ).asInstanceOf[Integer].intValue() );
+ else
+ gen.mkIntLit( Position.FIRSTPOS, FAIL );
+ }
+
+ def code_state_NEW(i: Int): Tree = {
+ var stateBody = code_delta( i, Label.DefaultLabel );
+ if( stateBody == null )
+ stateBody = code_fail();
+ val trans = dfa.deltaq.asInstanceOf[Array[HashMap]]( i );
+
+ val labs = dfa.labels().iterator();
+ while(labs.hasNext()) {
+ val label = labs.next();
+ val next = trans.get( label ).asInstanceOf[Integer];
+ val action = code_delta( i, label.asInstanceOf[Label] );
+ if( action != null ) {
+ /*assert*/ //stateBody != null : "stateBody is null";
+ stateBody = gen.If( currentMatches(label.asInstanceOf[Label] ),
+ action,
+ stateBody);
+ }
+ }
+ stateBody;
+ }
+ }
+}
diff --git a/sources/scala/tools/scalac/transformer/matching/LeftTracerInScala.scala b/sources/scala/tools/scalac/transformer/matching/LeftTracerInScala.scala
new file mode 100644
index 0000000000..f3254f0c77
--- /dev/null
+++ b/sources/scala/tools/scalac/transformer/matching/LeftTracerInScala.scala
@@ -0,0 +1,242 @@
+import scalac._;
+import scalac.ast._;
+import scalac.symtab._;
+import Tree._;
+import scalac.util.Names;
+
+import java.util._ ;
+
+import scala.tools.util.Position;
+//import scalac.transformer.matching._ ;
+import scalac.transformer.matching.CodeFactory ;
+import scalac.transformer.matching.DetWordAutom ;
+import scalac.transformer.matching.Label ;
+import scalac.transformer.matching.PartialMatcher ;
+package scala.tools.scalac.transformer.matching {
+
+class LeftTracerInScala(dfa: DetWordAutom, elementType: Type, owner: Symbol, cf: CodeFactory, val selector: Tree )
+extends TracerInScala( dfa, elementType, owner, cf ) {
+
+ final def defs = cf.defs;
+
+ /** symbol of the accumulator ( scala.SequenceList )
+ */
+ var accumSym: Symbol = _;
+ var accumType: Type = _;
+ var accumTypeArg: Type =_ ;
+
+ def _accumType(elemType: Type): Type = {
+ cf.SeqTraceType( elemType );
+ }
+
+
+ protected def initializeSyms(): Unit = {
+ this.funSym = owner.newLabel( pos,
+ cf.fresh.newName( "left" ));
+
+ this.iterSym = owner.newVariable( pos,
+ Modifiers.MUTABLE,
+ cf.fresh.newName( "iter" ))
+ .setType( cf._seqIterType( elementType ) ) ;
+
+ this.stateSym = owner.newVariable( pos,
+ Modifiers.MUTABLE,
+ cf.fresh.newName( "q" ))
+ .setType( defs.int_TYPE() ) ;
+
+ this.accumType = _accumType( elementType );
+ this.accumTypeArg = accumType.typeArgs()( 0 );
+ this.accumSym = owner.newVariable( pos, // accumulator
+ Modifiers.MUTABLE,
+ cf.fresh.newName( "acc" ))
+ .setType( accumType );
+
+ //this.funSym
+ // .setType( new Type.MethodType( new Symbol[] {
+ // accumSym, iterSym, stateSym},
+ // accumType));
+
+ this.funSym
+ .setType( new Type.MethodType( Predef.Array[Symbol] ( // dummy symbol MethodType
+ funSym.newVParam( pos, 0, cf.fresh.newName( "q" ), defs.int_TYPE()),
+ funSym.newVParam( pos, 0, cf.fresh.newName( "acc" ), accumType ) ),
+ accumType)); // result type = List[T]
+
+ this.resultSym = owner.newVariable(pos,
+ 0,
+ cf.fresh.newName("trace"))
+ .setType( accumType ) ;
+
+ this.curSym = owner.newVariable( pos, 0, Names.cur )
+ .setType( elementType );
+
+ this.hasnSym = owner.newVariable( pos, 0, Names.hasNext )
+ .setType( defs.boolean_TYPE() );
+
+ }
+
+ /* should throw an exception here really, e.g. MatchError
+ */
+ override def code_fail() = {
+ gen.Ident( accumSym.pos, accumSym );
+ }
+
+ /** returns translation of transition with label from i.
+ * returns null if there is no such transition(no translation needed)
+ */
+ override def code_delta(i: Int, label: Label): Tree = {
+ val target = dfa.delta( i, label );
+
+ /*
+ System.out.println("LeftTracer:calling dfa.delta("+i+","+label+")");
+ System.out.println("result: "+target);
+ */
+ if( target == null )
+ null;
+ else {
+ // (optimization) that one is a dead state (does not make sense for tracer)
+ /*
+ if( target == dfa.nstates - 1 )
+ return code_fail();
+ */
+
+ /*
+ Tree newAcc = cf.newSeqTraceCons(new Integer(i),
+ currentElem(),
+ _ref( accumSym ));
+ */
+ val hd = cf.newPair( gen.mkIntLit(cf.pos, i), currentElem() );
+ val newAcc = gen.mkNewCons( cf.pos,
+ accumTypeArg,
+ hd,
+ gen.Ident( cf.pos, accumSym ));
+
+ //return callFun( new Tree[] { newAcc , _iter(), gen.mkIntLit( cf.pos, target )} );
+ callFun( Predef.Array[Tree]( gen.mkIntLit( cf.pos, target.intValue() ), newAcc ) );
+ }
+ }
+
+
+ def code_body(): Tree = {
+
+ var body = code_error(); // never reached at runtime.
+
+ // state [ nstates-1 ] is the dead state, so we skip it
+
+ //`if( state == q ) <code_state> else {...}'
+ var i = dfa.nstates()-2;
+ while(i >= 0) {
+ body = code_state( i, body );
+ i = i - 1;
+ }
+ loadCurrentElem( body );
+ }
+
+ /** return code for state i of the dfa SAME AS IN SUPER, ONLY SINK IS GONE
+ */
+ def code_state(i: Int, elseBody: Tree): Tree = {
+
+ var runFinished: Tree = _; // holds result of the run
+ var finalSwRes: Int = 0;
+
+ runFinished = run_finished( i );
+
+ var stateBody: Tree = _ ; // 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
+
+ val trans = (dfa.deltaq.asInstanceOf[Array[HashMap]])( i );
+ val labs = (dfa.deltaq( i ).asInstanceOf[HashMap]).keySet().iterator();
+ while(labs.hasNext()) {
+ val label = labs.next();
+ val next = trans.get( label ).asInstanceOf[Integer];
+
+ val action = code_delta( i, label.asInstanceOf[Label] );
+
+ if( action != null ) {
+ stateBody = gen.If( currentMatches(label.asInstanceOf[Label]),
+ action,
+ stateBody);
+ }
+ }
+ stateBody = gen.If( cf.Negate( gen.Ident( cf.pos, hasnSym )),
+ runFinished,
+ stateBody );
+ gen.If( cf.Equals( _state(), gen.mkIntLit(cf.pos, i )),
+ stateBody ,
+ elseBody );
+ }
+
+ def getTrace(): Tree = {
+
+ initializeSyms();
+
+ cf.gen.mkBlock( cf.pos, Predef.Array[Tree] (
+ gen.ValDef( iterSym, cf.newIterator( selector, selector.getType() )),
+ gen.ValDef( stateSym, gen.mkIntLit( cf.pos, 0) ),
+ gen.ValDef( accumSym, gen.mkNil( cf.pos )),
+ gen.ValDef( resultSym,
+ gen.LabelDef( this.funSym,
+ Predef.Array[Ident] (
+ gen.Ident( pos, stateSym ),
+ gen.Ident( pos, accumSym )
+ ), code_body() /* code_body_new ? */ ))
+ ),
+ gen.Ident( cf.pos, resultSym ));
+ }
+
+ // calling the AlgebraicMatcher here
+ override def _cur_match(pat: Tree): Tree = {
+ //return gen.mkBooleanLit(cf.pos, true);
+
+ //System.out.println("calling algebraic matcher on type:"+pat.type);
+
+ val m = new PartialMatcher( owner,
+ currentElem(),
+ defs.boolean_TYPE() );
+
+ val res1 = if(containsBinding( pat )) {
+ pat.match {
+ case Sequence(pats) =>
+ gen.mkBooleanLit(cf.pos, true);
+ case _ =>
+ null
+ }
+ } else null;
+
+ if (res1 == null) {
+
+ am.construct( m, Predef.Array[Tree] (
+ cf.gen.CaseDef( pat,
+ gen.mkBooleanLit( cf.pos, true )),
+ cf.gen.CaseDef( cf.gen.Ident( pat.pos, defs.PATTERN_WILDCARD ),
+ gen.mkBooleanLit( cf.pos, false)) ),
+ false);
+ val res = am.toTree();
+ // debugprint ?
+ res;
+ } else null
+ }
+
+
+ /** return the accumulator + last state
+ */
+ override def run_finished(state: Int): Tree = {
+ val hd = cf.newPair( gen.mkIntLit( cf.pos, state ),
+ gen.mkDefaultValue(cf.pos,
+ elementType));
+ //System.err.println(hd.type);
+ gen.mkNewCons( cf.pos,
+ accumTypeArg,
+ hd,
+ gen.Ident( cf.pos, accumSym ));
+ }
+
+}
+}
diff --git a/sources/scala/tools/scalac/transformer/matching/RightTracerInScala.scala b/sources/scala/tools/scalac/transformer/matching/RightTracerInScala.scala
new file mode 100644
index 0000000000..b929b0ba70
--- /dev/null
+++ b/sources/scala/tools/scalac/transformer/matching/RightTracerInScala.scala
@@ -0,0 +1,502 @@
+/**
+ * $Id$
+ */
+
+import scalac._;
+import scalac.ast._;
+import scalac.symtab._;
+import Tree._;
+
+import java.util._ ;
+import Scope.SymbolIterator;
+
+import scalac.util.Name ;
+import scalac.util.Names ;
+
+import scala.tools.util.Position;
+
+import scalac.transformer.matching.CodeFactory ;
+import scalac.transformer.matching.DetWordAutom ;
+import scalac.transformer.matching.Label ;
+import scalac.transformer.matching.PartialMatcher ;
+
+package scala.tools.scalac.transformer.matching {
+
+ /** translate right tracer to code
+ * @param dfa determinized left tracer
+ * @param left nondeterm. left tracer (only needed for variables!)
+ * @param cf ...
+ * @param pat ?
+ * @param elementType ...
+ */
+class RightTracerInScala(dfa: DetWordAutom, seqVars: Set, owner: Symbol, cf: CodeFactory, pat:Tree, elementType: Type)
+extends TracerInScala( dfa, elementType, owner, cf ) {
+
+ final def defs = cf.defs;
+
+ val allVars: Set = collectVars( pat );
+
+ var varsToExport: Set = new HashSet(); // @todo HANDLE seqVars THESE GLOBALLY INSTEAD OF LOCALLY
+
+ varsToExport.addAll( allVars );
+ varsToExport.removeAll( seqVars );
+
+ var targetSym:Symbol = _;
+
+ var helpMap = new HashMap();
+ var helpMap2 = new HashMap();
+ var helpVarDefs = new TreeList();
+
+ val it = seqVars.iterator();
+ while(it.hasNext()) {
+ makeHelpVar( it.next().asInstanceOf[Symbol] );
+ }
+
+ val jt = allVars.iterator();
+ while(jt.hasNext()) {
+ val varSym = jt.next().asInstanceOf[Symbol];
+ if(( varSym.name.toString().indexOf("$") == -1 )
+ && ( !seqVars.contains( varSym ))) {
+ makeHelpVar( varSym, true );
+ }
+ }
+
+ //System.out.println("allVars: "+allVars);
+ //System.out.println("seqVars: "+seqVars);
+ //System.out.println("helpVarDefs now: "+helpVarDefs);
+
+ initializeSyms();
+
+ def makeHelpVar(realVar: Symbol): Unit = {
+ makeHelpVar( realVar, false );
+ }
+
+ /** makes a helpvar and puts mapping into helpMap, ValDef into helpVarDefs
+ */
+
+ def makeHelpVar(realVar: Symbol, keepType: Boolean): Unit = {
+ val helpVar = owner.newVariable( cf.pos,
+ 0,
+ cf.fresh.newName( realVar.name
+ .toString()+"RTIS" ));
+ var rhs: Tree = _;
+
+ //System.out.println("RTiS making helpvar : "+realVar+" -> "+helpVar);
+
+ if( keepType ) {
+ helpVar.setType( realVar.getType() );
+ rhs = gen.mkDefaultValue( cf.pos, realVar.getType() );
+ } else {
+ helpVar.setType( defs.LIST_TYPE(elementType) );
+ rhs = gen.mkNil( cf.pos );
+ }
+
+ helpMap.put( realVar, helpVar );
+ helpVar.flags = helpVar.flags | Modifiers.MUTABLE;
+ val varDef = gen.ValDef( helpVar, rhs );
+ //((ValDef) varDef).kind = Kinds.VAR;
+ helpVarDefs.append( varDef );
+
+ }
+
+ def prependToHelpVar(realVar: Symbol, elem:Tree): Tree = {
+ val hv = refHelpVar( realVar );
+ gen.Assign( hv, gen.mkNewCons( cf.pos, elementType, elem, hv ));
+ /*
+ return cf.Block(pos,
+ new Tree [] {
+ cf.debugPrintRuntime( "ASSIGN" ),
+ gen.Assign( hv, cf.newSeqCons( elem, hv ))
+ }, defs.UNIT_TYPE());
+ */
+ }
+
+ protected def initializeSyms(): Unit = {
+
+ this.funSym = owner.newLabel( pos,
+ cf.fresh.newName( "right" ));
+
+ this.iterSym = owner.newVariable( pos,
+ Modifiers.MUTABLE,
+ cf.fresh.newName("iter"))
+ .setType( cf.SeqTraceType( elementType ));
+
+ this.stateSym = owner.newVariable ( pos,
+ Modifiers.MUTABLE,
+ cf.fresh.newName("q"))
+ .setType( defs.int_TYPE() ) ;
+
+ this.curSym = owner.newVariable( pos,
+ Modifiers.MUTABLE,
+ cf.fresh.newName("cur"))
+ .setType( elementType ) ;
+
+ this.targetSym = owner.newVariable( pos,
+ Modifiers.MUTABLE,
+ cf.fresh.newName("p"))
+ .setType( defs.int_TYPE() ) ;
+
+ funSym.setType( new Type.MethodType( Predef.Array[Symbol] ( // dummy symbol MethodType
+ funSym.newVParam( pos, 0, cf.fresh.newName("iter"), cf.SeqTraceType( elementType )),
+ funSym.newVParam( pos, 0, cf.fresh.newName( "q" ), defs.int_TYPE()) ),
+ defs.void_TYPE() )); // result
+
+ }
+
+ // load current elem and trace
+ override def loadCurrentElem(body: Tree): Tree = {
+ gen.If( cf.isEmpty( _iter() ),
+ run_finished( 0 ), // we are done
+ gen.mkBlock( Predef.Array[Tree] (
+ gen.ValDef( this.targetSym,
+ cf.SeqTrace_headState( gen.Ident( pos, iterSym))),
+ gen.ValDef( this.curSym,
+ cf.SeqTrace_headElem( gen.Ident( pos, iterSym )))),
+ body )
+ );
+ }
+
+ /** see code_state0_NEW
+ */
+ def code_state0(elseBody: Tree) = { // careful, map Int to Int
+
+ gen.If( cf.Equals( _state(), gen.mkIntLit( cf.pos, 0 )),
+ code_state0_NEW(),
+ elseBody );
+
+ }
+
+ /** this one is special, we check the first element of the trace
+ * and choose the next state depending only on the state part
+ */
+ def code_state0_NEW(): Tree = { // careful, map Int to Int
+
+ val hmap = dfa.deltaq( 0 ).asInstanceOf[HashMap]; // all the initial states
+
+ var i = 0;
+ val n = hmap.keySet().size(); // all transitions defined
+
+ val tmapTag = new TreeMap();
+ val tmapBody = new TreeMap();
+ var it = hmap.keySet().iterator();
+ while(it.hasNext()) {
+ val targetL = it.next().asInstanceOf[Integer];
+ val targetR = hmap.get( targetL ).asInstanceOf[Integer];
+
+ val I = new Integer( i );
+ tmapTag.put( targetL, I );
+ tmapBody.put( I, callFun( Predef.Array[Tree] (
+ cf.SeqTrace_tail( _iter() ),
+ gen.mkIntLit( cf.pos, targetR.intValue() ) )));
+ i = i + 1;
+ }
+ i = 0;
+ val tags = new Array[Int]( n );
+ val targets = new Array[Tree]( n );
+ var jt = tmapTag.keySet().iterator();
+ while(jt.hasNext()) {
+ val tagI = jt.next().asInstanceOf[Integer];
+ tags( i ) = tagI.intValue();
+ val I = tmapTag.get( tagI ).asInstanceOf[Integer];
+ targets( i ) = tmapBody.get( I ).asInstanceOf[Tree];;
+ i = i + 1
+ }
+ gen.Switch( gen.Ident( pos, targetSym ),
+ tags,
+ targets,
+ code_error()/*cannot happen*/ );
+
+ }
+
+ override def currentMatches(label: Label): Tree = {
+ label.match {
+ case Label.Pair( target, theLab ) =>
+ cf.Equals( gen.mkIntLit( cf.pos, target.intValue() ),
+ current() );
+ case _ => throw new ApplicationError("expected Pair label");
+ }
+ }
+
+
+ override def code_state_NEW(i: Int): Tree = { // precondition i != 0
+ var stateBody = code_delta( i, Label.DefaultLabel );
+ if( stateBody == null ) {
+ stateBody = code_error();
+ }
+ val trans = dfa.deltaq.asInstanceOf[Array[HashMap]]( i );
+ val tmapTag = new TreeMap();
+ val tmapBody = new TreeMap();
+ var j = 0;
+ var labs = dfa.labels().iterator();
+ while(labs.hasNext()) {
+ val label = labs.next();
+ val next = trans.get( label ).asInstanceOf[Integer];
+ val action = code_delta( i, label.asInstanceOf[Label] );
+
+ if( action != null ) {
+ val J = new Integer( j );
+ tmapTag.put( label.asInstanceOf[Label.Pair].state, J );
+ tmapBody.put( J, action );
+
+ stateBody = gen.If( currentMatches( label.asInstanceOf[Label] ),
+ action,
+ stateBody);
+ }
+ j = j + 1;
+ }
+ val n = tmapTag.keySet().size();
+ j = 0;
+ val tags = new Array[int]( n );
+ val targets = new Array[Tree]( n );
+ val it = tmapTag.keySet().iterator();
+ while(it.hasNext()) {
+ val tagI = it.next().asInstanceOf[Integer];
+ tags( j ) = tagI.intValue();
+ val J = tmapTag.get( tagI ).asInstanceOf[Integer];
+ targets( j ) = tmapBody.get( J ).asInstanceOf[Tree];
+ j = j + 1;
+ }
+ if( n > 0 )
+ gen.Switch( gen.Ident( pos, targetSym ), tags, targets, code_error() );
+ else
+ code_error();
+ }
+
+ // calling the AlgebraicMatcher here
+ override def _cur_match(pat1: Tree): Tree = {
+ var pat = pat1;
+ //System.out.println("RTiS._cur_match("+pat.toString()+")");
+ //System.out.println("calling algebraic matcher on type:"+pat.type);
+
+ //System.err.println( "curT"+currentElem().type().widen() );
+ val m = new PartialMatcher( owner, //funSym,//this.funSym,
+ currentElem(),
+ defs.boolean_TYPE() );
+
+ val freshenMap = new HashMap(); // sym2exp -> new sym
+ val helpMap3 = new HashMap(); // new sym -> original sym
+
+ // "freshening": never use the same symbol more than once
+ // (in later invocations of _cur_match)
+
+ var it = varsToExport.iterator();
+ while(it.hasNext() ) {
+ val key = it.next().asInstanceOf[Symbol];
+ if( key.name.toString().indexOf("$") == -1 ) {
+ this.helpMap2.put( key, helpMap.get( key ));
+ // "freshening" by appending string ( a bit dangerous )
+ val newSym = key.cloneSymbol().setOwner( owner /*funSym*/ );
+ newSym.name = Name.fromString( key.name.toString() + "%" );
+ freshenMap.put( key, newSym );
+ helpMap3.put( newSym, helpMap.get( key ));
+ //System.out.println( "key: "+ key + " key.owner:"+key.owner());
+ //System.out.println( "newsym owner:"+newSym.owner());
+ } else {
+ freshenMap.put( key, key );
+ }
+ }
+
+ //System.out.println("RightTracerInScala:: -pat :"+pat.toString());
+ /*
+ System.out.println("RightTracerInScala - the seqVars"+seqVars);
+ System.out.println("RightTracerInScala - the varsToExport"+varsToExport);
+ */
+ //System.out.println("RightTracerInScala::freshenMap :"+freshenMap);
+
+ // "freshening"
+
+ /* TEST
+ */
+ val tc = new TreeCloner( cf.unit.global, freshenMap, Type.IdMap );
+
+ /*
+ Transformer tc = new Transformer(cf.unit.global) {
+ public Tree transform(Tree tree) {
+ tree = super.transform(tree);
+ if (tree.hasSymbol()) {
+ Object symbol = freshenMap.get(tree.symbol());
+ if (symbol != null) tree.setSymbol((Symbol)symbol);
+ }
+ return tree;
+ }
+ };
+ */
+ pat = tc.transform( pat );
+
+
+ //System.out.println("RightTracerInScala:: -pat( after subst ) :"+pat);
+
+
+ // val match { case <pat> => { <do binding>; true }
+ // case _ => false
+
+
+ val ts = new Array[Tree]( helpMap3.keySet().size() );
+ var j = 0;
+ var jt = helpMap3.keySet().iterator();
+ while(jt.hasNext()) {
+ val vsym = jt.next().asInstanceOf[Symbol];
+ val hv = helpMap3.get( vsym ).asInstanceOf[Symbol];
+ //hv.setType( defs.LIST_TYPE( elementType ) ) ; DEBUG ALARM ?
+ val refv = gen.Ident(cf.pos, vsym);
+ val refhv = gen.Ident(cf.pos, hv);
+ ts( j ) = gen.Assign( refhv, refv );
+ j = j + 1;
+ // System.out.println( "the assign" + res[ j - 1 ] );
+ }
+
+ val res = gen.mkBooleanLit( cf.pos, true ); // just `true'
+ val theBody = gen.mkBlock(ts, res);
+
+ am.construct( m, Predef.Array[Tree] (
+
+ cf.gen.CaseDef( pat, // if tree val matches pat -> update vars, return true
+ theBody/* "freshening */),
+ cf.gen.CaseDef( cf.gen.Ident( pat.pos, defs.PATTERN_WILDCARD ),
+ gen.mkBooleanLit( pat.pos, false )) ), // else return false
+ true // do binding please
+ );
+
+ am.toTree();
+ }
+
+ /** returns translation of transition with label from i.
+ * returns null if there is no such transition(no translation needed)
+ */
+ override def code_delta(i: Int , label: Label ): Tree = {
+ val hmap = dfa.deltaq( i ).asInstanceOf[HashMap];
+ val ntarget = hmap.get( label ).asInstanceOf[Integer];
+ var algMatchTree: Tree = null;
+ if( ntarget == null )
+ return null;
+
+ //System.out.println("delta("+i+","+label+")" );
+ var theLab: Label = null;
+ label.match {
+ case Label.Pair( state, lab2 )=>
+ //assert ntarget == state;
+ theLab = lab2;
+ lab2.match {
+ case Label.TreeLabel( pat ) =>
+ algMatchTree = _cur_match( pat );
+ case _ =>
+ }
+ case Label.DefaultLabel =>
+ throw new ApplicationError(); // should not happen
+ }
+ //assert dfa.qbinders != null : "qbinders ?";
+
+ var vars = dfa.qbinders( i );
+
+ //System.out.println("dfa.qbinders[ i ]"+vars);
+
+ if( null == vars ) vars = new Vector(); // TODO: make this more consistent
+ //assert vars != null;
+
+ val stms = new Array[Tree]( vars.size()
+ + { if (algMatchTree != null ) 1 else 0 });
+ var j = 0;
+ var it = vars.iterator();
+ while(it.hasNext()) {
+ val vble = it.next().asInstanceOf[Symbol];
+ val rhs = gen.Ident( pos, curSym );
+ stms( j ) = prependToHelpVar( vble , rhs);
+ j = j + 1;
+ }
+
+ if( algMatchTree != null ) {
+ stms( j ) = algMatchTree ;
+ j = j + 1
+ }
+
+ val value = callFun( Predef.Array[Tree] ( cf.SeqTrace_tail( _iter() ),
+ gen.mkIntLit( cf.pos, ntarget.intValue() ) ) );
+
+ gen.mkBlock( pos, stms, value );
+ }
+
+ override def stateWrap(i: Int): Tree = {
+ if( i == 0 )
+ code_state0_NEW();
+ else
+ code_state_NEW( i );
+ }
+
+ /* returns statements that do the work of the right-transducer
+ */
+ def getStms(trace: Tree, unit: CompilationUnit, body: Tree): Tree = {
+
+ val stms = new TreeList();
+ val loopbody = code_body_NEW();
+
+ stms.append( gen.ValDef( iterSym, trace ) );
+ stms.append( gen.ValDef( stateSym, gen.mkIntLit( cf.pos, 0 ) ) );
+ stms.append( helpVarDefs );
+ stms.append( gen.LabelDef( this.funSym,
+ Predef.Array[Ident] (
+ gen.Ident( pos, iterSym ),
+ gen.Ident( pos, stateSym )
+ ), loopbody ));
+
+ // bind variables handled by this righttracer
+ var it = seqVars.iterator();
+ while(it.hasNext()) {
+ stms.append( bindVar( it.next().asInstanceOf[Symbol] ) );
+ }
+
+ val treeCloner = new Transformer(unit.global) {
+ override def transform(tree1: Tree): Tree = {
+ val tree = super.transform(tree1);
+ if (tree.hasSymbol()) {
+ val symbol = helpMap2.get(tree.symbol());
+ if (symbol != null) tree.setSymbol(symbol.asInstanceOf[Symbol]);
+ }
+ tree;
+ }
+ };
+
+ gen.mkBlock(stms.toArray(), treeCloner.transform( body ));
+ }
+
+
+
+ /** return the accumulator. (same as in LeftTracerInScala)
+ * todo: move tree generation of Unit somewhere else
+ */
+ override def run_finished(state: Int): Tree = {
+ gen.mkUnitLit(Position.FIRSTPOS);
+ }
+
+ def current() = { gen.Ident( pos, targetSym );}
+
+ def refHelpVar(realVar: Symbol) = {
+ val hv = helpMap.get( realVar ).asInstanceOf[Symbol];
+ //assert hv != null : realVar;
+ gen.Ident(Position.FIRSTPOS, hv);
+ }
+
+ def assignToHelpVar(realVar: Symbol, rhs: Tree): Tree = {
+ val hv = refHelpVar( realVar );
+ gen.Assign( hv, rhs );
+ }
+
+ def bindVar(realVar: Symbol): Tree = {
+ val hv = refHelpVar( realVar );
+ /*
+ System.out.println("binding realVar.name "+realVar.name+" type:"+realVar.type()+" to hv type:"+hv.type());
+ realVar.setOwner( owner );
+ System.out.println("is same as realVar"+realVar.type().isSameAs( elementType ));
+ System.out.println("is same as hv"+realVar.type().isSameAs( hv.type() ));
+ if( realVar.type().isSameAs( elementType ))
+ return gen.ValDef( realVar, cf.SeqList_head( hv ));
+ else
+ return gen.ValDef( realVar, hv );
+ */
+ if( realVar.getType().isSameAs( hv.getType())) {
+ gen.ValDef( realVar, hv ); // e.g. x @ _*
+ } else
+ gen.ValDef( realVar, cf.SeqList_head( hv ));
+ }
+}
+}
+
diff --git a/sources/scala/tools/scalac/transformer/matching/SequenceMatcher.scala b/sources/scala/tools/scalac/transformer/matching/SequenceMatcher.scala
new file mode 100644
index 0000000000..cbf1722f8f
--- /dev/null
+++ b/sources/scala/tools/scalac/transformer/matching/SequenceMatcher.scala
@@ -0,0 +1,174 @@
+
+
+import scalac._;
+import scalac.ast.Tree;
+import Tree._;
+
+ //import scala.compiler.printer.XMLAutomPrinter ; // DEBUGGING\
+
+import scalac.ast._ ;
+import scalac.symtab._ ;
+
+import java.util._ ;
+
+import scala.tools.util.Position;
+import scalac.transformer.matching.PatternTool;
+import scalac.transformer.matching.PartialMatcher;
+
+import scalac.transformer.matching.{BerrySethi, BindingBerrySethi};
+import scalac.transformer.matching.CollectVariableTraverser;
+import scalac.transformer.matching.CodeFactory;
+import scalac.transformer.matching.DetWordAutom;
+import scalac.transformer.matching.Label;
+import scalac.transformer.matching.NondetWordAutom;
+import scalac.transformer.matching.PartialMatcher;
+
+package scala.tools.scalac.transformer.matching {
+/** 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.
+ */
+
+class SequenceMatcher(unit: CompilationUnit) extends PatternTool(unit) {
+
+ final val IGNORED = new Integer(42);
+
+ var cf: CodeFactory = _;
+ var _m: PartialMatcher = _;
+
+ var bbuild: BindingBerrySethi = null;
+
+ /** collects variables
+ * @return all variables bound by this binding nfa
+ */
+ def collectNfaVariables(nfa: NondetWordAutom): Set = {
+ val seqVars = new HashSet();
+ var j = 0;
+ while(j < nfa.nstates()) {
+ if( nfa.qbinders( j ) != null )
+ seqVars.addAll( nfa.qbinders( j ) );
+ j = j + 1
+ }
+ seqVars;
+ }
+
+
+ /** translates the det/switching automaton to scala code
+ * precondition: pat.type() corresponds to element type
+ */
+ def addBinderToBody( pat:Tree , body:Tree ): Tree = {
+ if( bbuild == null )
+ bbuild = new BindingBerrySethi(unit);
+
+ val elementType = cf.getElemType_Sequence( pat.getType() );
+
+ // (a) build *binding* nfa (sequential machine)
+ val left = bbuild.automatonFrom( pat, IGNORED );
+ val right = bbuild.revnfa;
+
+ // (b) determinize + translate L
+
+ val dLeft = new DetWordAutom( left );
+
+ val ltis = new LeftTracerInScala( dLeft, elementType, _m.owner, cf, _m.selector);
+
+ val trace = ltis.getTrace();
+
+ // (c) determinize + translate R
+
+ val dRight = new DetWordAutom( right, left, dLeft );
+
+ val seqVars = collectNfaVariables( left );
+ //System.out.println("seqVars here are:"+seqVars);
+ val rtis = new RightTracerInScala( dRight, seqVars, _m.owner,
+ cf, pat, elementType );
+
+ // !!! Tree stms2 = rtis.getStms( theTrace, unit, body );
+ // !!! gen.mkBlock_( body.pos, trace, stms2 );
+ val stms2 = rtis.getStms( trace, unit, body );
+ stms2;
+ }
+
+ private def buildNfas( pat:Array[Tree] ): Array[NondetWordAutom] = {
+ val build = new BerrySethi(unit);
+ val manyNfa = new Array[NondetWordAutom]( pat.length );
+ var i = 0;
+ while( i < pat.length ) {
+ manyNfa( i ) = build.automatonFrom( pat( i ),
+ new Integer( i ));
+ i = i + 1;
+ //manyNfa[ i ].print();
+ }
+ 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
+ */
+ def construct(_m: PartialMatcher, pat: Array[Tree] , body: Array[Tree] , defcase1: Tree, doBinding: Boolean ): Unit = {
+ var defaultCase = defcase1;
+ this._m = _m;
+ //assert body.length == pat.length;
+ if( defaultCase == null )
+ defaultCase = cf.ThrowMatchError( cf.pos, _m.resultType );
+
+ this.cf = new CodeFactory( unit, _m.pos );
+
+ val seqType = pat( 0 ).getType();
+ val elementType = cf.getElemType_Sequence( seqType );
+
+ // STEP 1 - build nfas for each pattern
+
+ val manyNfa = buildNfas( pat );
+
+ // STEP 2 - recognizing
+
+ // (a) merge nfas into one if necessary
+ val nfa = if(pat.length > 1) new NondetWordAutom( manyNfa ) else manyNfa( 0 );
+
+ //nfa.print();
+
+ // (b) determinize
+ val dfa = new DetWordAutom( nfa );
+
+ // (c) translate to scala code
+ val scalaAut =
+ new WordAutomInScala( dfa,
+ elementType,
+ _m.owner,
+ cf,
+ unit.global.target == Global.TARGET_JVM );
+ scalaAut.translate();
+
+ // STEP 3 - binding
+
+ var newbody:Array[Tree] = _;
+ if( !doBinding )
+ newbody = body;
+ else { // this is done in the body of the matching case
+ newbody = new Array[Tree](body.length);
+ var i = 0;
+ while(i < body.length) {
+ if( !new CollectVariableTraverser().containsBinding( pat( i ) ) )
+ newbody( i ) = body( i ); // no need for binding
+ else
+ newbody( i ) = addBinderToBody( pat( i ), body( i ) );
+ i = i + 1;
+ }
+ }
+ _m.tree = scalaAut.getMatcherSwitch( _m.selector,
+ defaultCase,
+ newbody,
+ _m.resultType );
+ } // construct (PartialMatcher, Tree[], Tree[], Tree, boolean )
+
+ } // class SequenceMatcher
+ }
diff --git a/sources/scala/tools/scalac/transformer/matching/TracerInScala.scala b/sources/scala/tools/scalac/transformer/matching/TracerInScala.scala
new file mode 100644
index 0000000000..393d97aa60
--- /dev/null
+++ b/sources/scala/tools/scalac/transformer/matching/TracerInScala.scala
@@ -0,0 +1,27 @@
+import scalac.ast.Tree;
+import scalac.symtab.Symbol;
+import scalac.symtab.Type;
+import scalac.transformer.matching.CodeFactory ;
+import scalac.transformer.matching.CollectVariableTraverser ;
+import scalac.transformer.matching.DetWordAutom ;
+
+package scala.tools.scalac.transformer.matching {
+/** @todo: factor common things of LeftTracerInScala and RightTracerInScala
+ */
+class TracerInScala(dfa: DetWordAutom, elementType: Type, owner: Symbol, cf: CodeFactory )
+extends Autom2Scala(dfa, elementType, owner, cf) {
+
+ override var optimize = true;
+
+ final def collectVars(pat: Tree) = {
+ val c = new CollectVariableTraverser();
+ c.collectVars(pat)
+ }
+
+ final def containsBinding(pat: Tree) = {
+ val c = new CollectVariableTraverser();
+ c.containsBinding(pat);
+ }
+
+}
+}
diff --git a/sources/scala/tools/scalac/transformer/matching/WordAutomInScala.scala b/sources/scala/tools/scalac/transformer/matching/WordAutomInScala.scala
new file mode 100644
index 0000000000..916dfb51af
--- /dev/null
+++ b/sources/scala/tools/scalac/transformer/matching/WordAutomInScala.scala
@@ -0,0 +1,176 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+\* */
+
+// $Id$
+
+
+
+import scala.tools.util.Position;
+
+import scalac._;
+import scalac.ast.Tree;
+import scalac.ast.TreeGen;
+import scalac.symtab.Type;
+import scalac.symtab.Symbol;
+import scalac.symtab.Modifiers; // test
+//import scalac.typechecker.*;
+import Tree._;
+
+import java.util._;
+import scala.tools.scalac.util.NewArray;
+
+import scalac.transformer.matching.CodeFactory;
+import scalac.transformer.matching.DetWordAutom;
+import scalac.transformer.matching.Label;
+import scalac.transformer.matching.PartialMatcher;
+import scalac.util.Names;
+
+package scala.tools.scalac.transformer.matching {
+ /** translates a recognizer to scala code
+ */
+
+ /** constructor
+ * @param dfa the dfa that is to be translated
+ * @param elementType type of the objects in the sequence
+ * @param owner the owner of the pattern match
+ * @param cf code factory
+ * @param optim flag that indicates whether to optimize
+ * @return an object that translates the dfa
+ */
+ class WordAutomInScala(dfa: DetWordAutom, elementType: Type, owner: Symbol, cf: CodeFactory, optim: Boolean )
+ extends Autom2Scala(dfa, elementType, owner, cf) {
+
+ final def defs = cf.defs;
+ this.optimize = this.optimize && optim;
+ var theDefDef: Tree = _ ;
+
+ def getMatcherSwitch(selector: Tree, failTree: Tree, body: Array[Tree], resultType: Type ): Tree = {
+
+ var result: Tree = _;
+
+ /*
+ boolean insane = true; // if you set this to false, you get some VerifyErrors
+ // seems fixed
+ if( insane ) { // cascading ifs
+
+ Tree cond[] = new Tree[body.length];
+ for( int i = body.length - 1; i >= 0; i-- ) {
+ cond[i] = cf.Equals(_swres(), gen.mkIntLit( cf.pos, i ));
+ }
+ result = cf.Switch( cond, body, failTree );
+
+ } else { // real switch
+ */
+ val tags = new Array[int](body.length);
+ var i = body.length - 1;
+ while( i >= 0 ) {
+ tags(i) = i;
+ i = i - 1
+ }
+ result = gen.Switch( _swres(), tags, body, failTree );
+
+ //}
+
+ result = cf.gen.mkBlock( cf.pos,
+ NewArray.Tree (
+ gen.ValDef( iterSym, cf.newIterator( selector )),
+ gen.ValDef( stateSym, gen.mkIntLit( cf.pos, 0) ),
+ gen.ValDef( resultSym, theDefDef )),
+ result );
+ //unit.global.debugPrinter.print( result );
+ result;
+ }
+
+ protected def initializeSyms(): Unit = { // TEST
+
+ this.funSym = owner.newLabel( pos,
+ cf.fresh.newName( "matcher" ));
+
+ this.iterSym = owner.newVariable( pos,
+ Modifiers.MUTABLE,
+ cf.fresh.newName("iter"))
+ .setType( cf._seqIterType( elementType ) ) ;
+
+ this.stateSym = owner.newVariable( pos,
+ Modifiers.MUTABLE,
+ cf.fresh.newName("q"))
+ .setType( defs.int_TYPE() ) ;
+
+ this.resultSym = owner.newVariable( pos,
+ Modifiers.MUTABLE,
+ cf.fresh.newName("swRes"))
+ .setType( defs.int_TYPE() ) ;
+
+ this.funSym
+ .setType( new Type.MethodType( Predef.Array[Symbol] (
+ funSym.newVParam( pos, 0, cf.fresh.newName("q"), defs.int_TYPE())
+ ), defs.int_TYPE() ));
+
+ this.curSym = owner.newVariable( pos, 0, Names.cur )
+ .setType( elementType );
+
+ this.hasnSym = owner.newVariable( pos, 0, Names.hasNext )
+ .setType( defs.boolean_TYPE() );
+
+ }
+
+ /** code for the return value of the automaton translation
+ */
+ override def run_finished( state: Int): Tree = { // T E S T
+ if( dfa.isFinal( state ))
+ gen.mkIntLit(Position.FIRSTPOS, dfa.finals.get( new Integer( state ) ).asInstanceOf[Integer].intValue() );
+ else
+ gen.mkIntLit( Position.FIRSTPOS, FAIL );
+ }
+
+
+ // calling the /*AlgebraicMatcher*/PatternMatcher here
+ override def _cur_match(pat: Tree): Tree = { // TE ST
+ val m = new PartialMatcher( this.owner, /* owner*/
+ currentElem(), /* root */
+ defs.boolean_TYPE() /* restype */);
+
+ am.construct( m, Predef.Array[Tree] (
+ cf.gen.CaseDef( pat,
+ gen.mkBooleanLit( pat.pos, true )),
+ cf.gen.CaseDef( cf.gen.Ident(pat.pos, defs.PATTERN_WILDCARD),
+ gen.mkBooleanLit( pat.pos, false )) ),
+ false);
+ am.toTree();
+ }
+
+ /** do the translation
+ */
+ def translate(): Unit = {
+ initializeSyms();
+ val tb = code_body_NEW();
+ //theDefDef = gen.DefDef(this.funSym, tb);
+ theDefDef = gen.LabelDef(this.funSym, Predef.Array[Ident] ( /*(Ident)_iter(),*/ _state().asInstanceOf[Ident] ), tb);
+ }
+
+ /** ...
+ * @return returns translation of transition with label from i.
+ * returns null if there is no such transition
+ * (no translation needed)
+ */
+ override def code_delta(i: Int, label: Label): Tree = {
+ val target = dfa.delta(i, label);
+
+ if (target == null)
+ label.match {
+ case Label.DefaultLabel =>
+ code_error(); // this may not happen !
+ case _ =>
+ null; // not good
+ }
+ else if (target.intValue() == dfa.nstates() - 1) // that one is a dead state
+ code_fail();
+ else
+ callFun(Predef.Array[Tree]( gen.mkIntLit( cf.pos, target.intValue() )));
+ }
+
+ }
+}