diff options
author | buraq <buraq@epfl.ch> | 2003-07-07 17:01:25 +0000 |
---|---|---|
committer | buraq <buraq@epfl.ch> | 2003-07-07 17:01:25 +0000 |
commit | 35173713d15ed338d0874c03791d80f0c79baa69 (patch) | |
tree | 1bfcff544186d97df28c7a2a8af83316250b3608 /sources | |
parent | aa4085f651c79d9da3a5db6194b9cc4d0a8cf041 (diff) | |
download | scala-35173713d15ed338d0874c03791d80f0c79baa69.tar.gz scala-35173713d15ed338d0874c03791d80f0c79baa69.tar.bz2 scala-35173713d15ed338d0874c03791d80f0c79baa69.zip |
handle matching with if pat contains reg op Alg...
handle matching with if pat contains reg op AlgebraicMatcher
Diffstat (limited to 'sources')
5 files changed, 733 insertions, 19 deletions
diff --git a/sources/scalac/transformer/TransMatch.java b/sources/scalac/transformer/TransMatch.java index f73fba1353..e558d88ce8 100644 --- a/sources/scalac/transformer/TransMatch.java +++ b/sources/scalac/transformer/TransMatch.java @@ -18,6 +18,8 @@ import scalac.util.*; // Names import Tree.*; import scalac.transformer.matching.PatternMatcher ; +import scalac.transformer.matching.TestRegTraverser ; +import scalac.transformer.matching.AlgebraicMatcher ; /** A transformer for expanding match expressions into * flat sequences of .is and .as method calls @@ -91,14 +93,30 @@ public class TransMatch extends OwnerTransformer { } protected Tree transform(Tree root, CaseDef[] cases, Type restpe) { - PatternMatcher pm = new PatternMatcher( unit, infer ); - Matcher matcher = new Matcher( currentOwner, root, restpe ); - - pm.construct( matcher, cases ); - if (global.log()) { - global.log("internal pattern matching structure"); - pm.print(); - } + boolean containsReg = false; + int i = 0; + Matcher matcher; + + while(( !containsReg )&&( i < cases.length )) + containsReg |= TestRegTraverser.apply( cases[ i++ ] ); + + if( containsReg ) + { + AlgebraicMatcher am = new AlgebraicMatcher( unit, infer ); + matcher = new Matcher( currentOwner, root, restpe ); + am.construct( matcher, cases ); + } + else + { + PatternMatcher pm = new PatternMatcher( unit, infer ); + matcher = new Matcher( currentOwner, root, restpe ); + + pm.construct( matcher, cases ); + if (global.log()) { + global.log("internal pattern matching structure"); + pm.print(); + } + } return matcher.tree; } diff --git a/sources/scalac/transformer/matching/AlgebraicMatcher.java b/sources/scalac/transformer/matching/AlgebraicMatcher.java new file mode 100644 index 0000000000..e89383087e --- /dev/null +++ b/sources/scalac/transformer/matching/AlgebraicMatcher.java @@ -0,0 +1,704 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scalac.transformer.matching; + +import scalac.*; +import scalac.ast.*; +import scalac.symtab.*; +import scalac.typechecker.*; + +import PatternNode.*; +import Tree.*; + +import scalac.transformer.TransMatch.Matcher ; +import scalac.util.Name ; +//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 PatternTool { + + //public static final Name RESULT_N = Name.fromString("$result"); + public static final String RESULT_N = "amResult"; + + Matcher _m; + + // the following instance variables are inherited from AbstractMatcher + // unit, fresh, make, defs, gen, infer, statics, trueSym, falseSym; + + /** the root of the pattern node structure + */ + PatternNode root; + + /** the symbol of the result variable + */ + Symbol resultVar; + + PatternNodeCreator mk; + CodeFactory cf; + + boolean doBinding; + + /** constructor + */ + public AlgebraicMatcher( Unit unit, Infer infer ) { + super( unit, infer ); + } + + /** 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.doBinding = doBinding; + this._m = m; + initialize(); + for( int i = 0; i < cases.length; i++ ) { + addCase( (CaseDef) cases[i], i); + } + _m.tree = toTree(); + } + + + /** initializes this AlgebraicMatcher, see Matcher.initialize + */ + void initialize() { + + this.mk = new PatternNodeCreator( unit, infer, _m.owner/*_m.clazzOwner*/ ); + this.cf = new CodeFactory( unit, infer /*, _m.pos*/ ); + + this.root = mk.ConstrPat(_m.pos, + _m.selector.type); + this.root.and = mk.Header(_m.pos, + _m.selector.type, + gen.Ident( _m.pos, root.symbol() ) + .setType(_m.selector.type)); + + this.resultVar = new TermSymbol(_m.pos, + cf.fresh.newName(RESULT_N), + _m.owner, + 0); + //this.resultType = resultType; + this.resultVar.setType( _m.resultType ); + + //System.out.println(" constructed matcherDefs "); + } + + /** return the analyzed type + */ + public Type typeOf(Symbol sym) { + return sym.type(); + } + + /** return the analyzed type + */ + public Type typeOf0(Symbol sym) { + return sym.typeAt(unit.global.PHASE.ANALYZER.id); + } + + /** factories + */ + + public void updateBody(Body tree, ValDef[] bound, Tree guard, Tree body) { + if (tree.guard[tree.guard.length - 1] == Tree.Empty) + unit.error(body.pos, "unreachable code"); + // BINDING BELOW SEQUENCE + //System.out.println("AlgebraicMatcher::updateBody ... , freeVars"+_m.freeVars); + /* + for( int i=0; i < bound.length; i++ ) + _m.freeVars.add( bound[ i ].symbol() ); + */ + ValDef[][] bd = new ValDef[tree.bound.length + 1][]; + Tree[] ng = new Tree[tree.guard.length + 1]; + Tree[] nb = new Tree[tree.body.length + 1]; + System.arraycopy(tree.bound, 0, bd, 0, tree.bound.length); + System.arraycopy(tree.guard, 0, ng, 0, tree.guard.length); + System.arraycopy(tree.body, 0, nb, 0, tree.body.length); + bd[bd.length - 1] = bound; + ng[ng.length - 1] = guard; + nb[nb.length - 1] = body; + tree.bound = bd; + tree.guard = ng; + tree.body = nb; + } + + /* + public Tree copy(Tree tree) { + return tree; // insert copy function here + } + */ + + /** convenience method, see addCase below + */ + public void addCase(CaseDef tree, int case_index) { + //System.out.println( "addCase(" + + // TextTreePrinter.toString(tree.pat) + + // ")" ); + addCase(tree.pos, tree.pat, tree.guard, tree.body, case_index); + //root.and.prettyPrint(); + } + /** adds a case definition to the intermediate presentation + */ + protected CaseEnv addCase(int pos, Tree pat, Tree guard, Tree body, int case_index) { + // TMP + /* + System.out.print("AM: addCase... pattern has variables:"); + CollectVariableTraverser cvt = new CollectVariableTraverser(); + cvt.traverse( pat ); + System.out.println(cvt.vars); + */ + + // TMP + CaseEnv env = new CaseEnv( _m.owner, unit ); + + //PatternNode matched = match(pat, root); + PatternNode target = enter1(pat, null /*-1*/, root, root.symbol(), env, case_index); + //if (target.and != null) + // unit.error(pat.pos, "duplicate case"); + + /* + System.out.print( "AM.addCase boundvars:{"); + ValDef bvs[] = env.boundVars(); + for( int j = 0; j < bvs.length; j++ ) + System.out.print(" "+bvs[ j ].symbol() ); + */ + + if (target.and == null) + target.and = mk.Body(pos, env.boundVars(), guard, body); + else if (target.and instanceof Body) + updateBody((Body)target.and, env.boundVars(), guard, body); + else + unit.error(pat.pos, "duplicate case"); + + return env; + } + + + protected Tree[] patternArgs(Tree tree) { + switch (tree) { + case Apply(_, Tree[] args): + return args; + default: + return Tree.EMPTY_ARRAY; + } + } + + protected Type getConstrType(Type tpe) { + return tpe; + } + + protected Type getHeaderType(Type tpe) { + switch (tpe) { + case PolyType(_, Type res): + return res; + default: + return tpe; + } + } + + /** constructs a pattern node depending on the case of argument `tree' + * @param tree the pattern node that needs to be translated + * @param castType cast type of the position that is tested + * @param selector selector tree of the position that is tested + * @param env an environment + */ + + protected PatternNode patternNode(Tree tree, + Type castType, + Tree selector, + CaseEnv env, + int case_index) { + Type theType = getConstrType( tree.type ); + switch (tree) { + case Apply(Tree fn, Tree[] args): // pattern with args + if (args.length == 1 && (tree.type.symbol().flags & Modifiers.CASE) == 0) + switch (args[0]) { + case Sequence(Tree[] ts): + PatternNode res = mk.ConstrPat( tree.pos, theType ); + res.and = mk.SequencePat(tree.pos, tree.type, ts.length, args[0]); + return res; + } + return mk.ConstrPat(tree.pos, theType); + case Typed(Ident(Name name), Tree tpe): // typed pattern + theType = getConstrType( tpe.type ); + assert (env != null ) : "env is null"; + if (/*(env != null) &&*/ (name != WILDCARD_N)) + env.newBoundVar(tree.pos, + ((Tree.Typed)tree).expr.symbol(), + theType, + selector); + if (castType.isSubType( theType )) + // castType is a subtype of theType + return mk.DefaultPat( tree.pos, theType ); + else + return mk.ConstrPat( tree.pos, theType ); + case Bind(Name name, Ident(Name id)): // x @ _ + if( id == WILDCARD_N ) { + env.newBoundVar(tree.pos, + tree.symbol(), + theType, + selector); + return mk.DefaultPat(tree.pos, getConstrType(castType)); + } + throw new ApplicationError("cannot handle "+tree); + case Ident(Name name): // pattern without args or variable + if (tree.symbol().isPrimaryConstructor()) + return mk.ConstrPat(tree.pos, theType); + else if (name.isVariable()) { + assert (env != null ) : "env is null"; + if (/*(env != null) &&*/ (name != WILDCARD_N)) + env.newBoundVar(tree.pos, + tree.symbol(), + theType, + selector); + return mk.DefaultPat(tree.pos, getConstrType(castType)); + } else + return mk.VariablePat(tree.pos, tree); + case Select(_, Name name): // variable + if (tree.symbol().isPrimaryConstructor()) + return mk.ConstrPat(tree.pos, theType); + else + return mk.VariablePat(tree.pos, tree); + case Literal(Object value): + return mk.ConstantPat(tree.pos, theType, value); + + case Sequence( _ ): + throw new ApplicationError("Illegal pattern"); + //return mk.SequencePat(tree.pos, tree, case_index); + //return mk.SequencePat(tree.pos, null, 0, tree); + + //case Subsequence( _ ): // this may not appear here. + /*case Bind( Name n, Tree t ): // ignore for now, treat as var x + + return patternN( gen.Ident( tree.pos, tree.symbol() ), + castType, + headerSel + env, + case_index); + */ + //case Alternative( _ ): // ignore for now + default: + throw new ApplicationError("cannot handle "+tree); + } + } + + /** 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; + } + } + + /** convenience method, if target there is a ConstrPat, + * the use its sym instead of the argument given. + */ + /* + public PatternNode eneter(Tree pat, + Symbol typeSym, //int index, + PatternNode target, + Symbol casted, + CaseEnv env, + int case_index) { + switch (target) { + case ConstrPat(Symbol newCasted): + return enter1(pat, typeSym, target, newCasted, env, case_index); + default: + return enter1(pat, typeSym, target, casted, env, case_index); + } + } +*/ + /** the main enter function. + * @param typeSym + * @param target we hang the result to the .and successor of this node, + * possibly creating a new header. + */ + public PatternNode enter1(Tree pat, + //int index, + Symbol typeSym, + PatternNode target, + Symbol casted, + CaseEnv env, + int case_index) { + //System.out.println("enter(" + pat + ", " + typeSym /*index*/ + ", " + target + ", " + casted + ")"); + // get pattern arguments (if applicable) + Tree[] patArgs = patternArgs(pat); + // get case fields + assert patArgs.length == nCaseComponents(pat); + // advance one step in pattern + Header curHeader = (Header)target.and; + // check if we have to add a new header + if (curHeader == null) { + //assert index >= 0 : casted; + // <casted>.as[ <caseFieldAccessor[ index ]> ] + + assert typeSym != null; + /* + Symbol typeSym = ((ClassSymbol) casted.type().symbol()) + .caseFieldAccessor(index); + */ + Type castType = getHeaderType( typeOf0( typeSym )); + target.and = curHeader = + mk.Header(pat.pos, + castType, + make.Apply(pat.pos, + make.Select(pat.pos, + gen.Ident(pat.pos, casted), + typeSym.name) + .setType(Type.MethodType(Symbol.EMPTY_ARRAY, + castType)) + .setSymbol( typeSym ), + Tree.EMPTY_ARRAY).setType( castType )); + // translate the root of `pat' + curHeader.or = patternNode(pat, + curHeader.type, + curHeader.selector, + env, + case_index); + // translate the args of `pat' + return enter(patArgs, curHeader.or, casted, env, case_index); + } + // find most recent header - (the last -next- successor of curHeader) + while (curHeader.next != null) + curHeader = curHeader.next; + // translate the root of `pat' + PatternNode patNode = patternNode(pat, + curHeader.type, + curHeader.selector, + env, + case_index); + PatternNode next = curHeader; + // enter node + while (true) + if (superPat(next, patNode)) + // next is of the same kind as patNode and matches (supertype) + return enter(patArgs, next, casted, env, case_index); + else if (isDefaultPat(next) || + ((next.or == null) && isDefaultPat(patNode))) { + curHeader.next = mk.Header(patNode.pos, + curHeader.type, curHeader.selector); + curHeader.next.or = patNode; + return enter(patArgs, + patNode, + casted, + env, + case_index); + } + else if (next.or == null) + return enter(patArgs, next.or = patNode, casted, env, case_index); + else + next = next.or; + } + + /** calls enter for an array of patterns, see enter + */ + public PatternNode enter(Tree[] pats, PatternNode target, Symbol casted, CaseEnv env, int case_index) { + switch (target) { + case ConstrPat(Symbol newCasted): + casted = newCasted; + } + for (int i = 0; i < pats.length; i++) { + Symbol typeSym = ((ClassSymbol) casted.type().symbol()) + .caseFieldAccessor( i ); + target = enter1(pats[i], typeSym /*i*/, target, casted, env, case_index); + } + return target; + } + + protected int nCaseComponents(Tree tree) { + switch (tree) { + case Apply(Tree fn, _): + Type tpe = typeOf(tree.type.symbol().constructor()); + //System.out.println("~~~ " + tree.type() + ", " + tree.type().symbol().constructor()); + switch (tpe) { + // I'm not sure if this is a good idea, but obviously, currently all case classes + // without constructor arguments have type NoType + case NoType: + return 0; + case MethodType(Symbol[] args, _): + return args.length; + case PolyType(Symbol[] tvars, MethodType(Symbol[] args, _)): + return args.length; + case PolyType(Symbol[] tvars, _): + return 0; + default: + throw new ApplicationError("not yet implemented;" + + "pattern matching for " + tree + ": " + tpe); + } + } + return 0; + } + + +//////////// generator methods + + public Tree toTree() { + TreeList ts = new TreeList(); + ts.append( gen.ValDef(_m.pos, root.symbol(), _m.selector )); + ts.append( gen.ValDef(_m.pos, resultVar, Tree.Empty )); + ts.append( cf.If( toTree(root.and), + gen.Ident( _m.pos, resultVar ), + cf.ThrowMatchError( _m.pos, _m.resultType ))); + /* + make.If( + _m.pos, + toTree(root.and), + gen.Ident( _m.pos, resultVar ), + cf.ThrowMatchError( _m.resultType )).type( _m.resultType )); + */ + return cf.Block(_m.pos, ts.toArray(), _m.resultType); + } + + protected Tree toTree(PatternNode node) { + Tree res = gen.mkBooleanLit( node.pos, false ); + while (node != null) + switch (node) { + case Header(Tree selector, Header next): + res = cf.Or(res, toTree(node.or, selector)); + node = next; + break; + case Body(ValDef[][] bound, Tree[] guard, Tree[] body): + for (int i = guard.length - 1; i >= 0; i--) { + Tree[] ts; + if( doBinding ) { + ts = new Tree[bound[i].length + 1]; + System.arraycopy(bound[i], 0, ts, 0, bound[i].length); + } else + ts = new Tree[ 1 ]; + + // FOR BIN + /* + System.out.print("AM.toTree(Body(...)) ValDefs: "); + for( int j = 0; j < bound[i].length; j++ ) + System.out.print(" "+bound[i][j].symbol()); + System.out.println(); + */ + //System.out.print("freeVars: "+_m.freeVars); + + int last = ts.length - 1; + ts[ last ] = cf.Block(body[i].pos, + new Tree[]{ + gen.Assign(gen.Ident( body[i].pos, resultVar ), + body[i]), + gen.mkBooleanLit(body[i].pos, true) + }, defs.BOOLEAN_TYPE); + if (guard[i] != Tree.Empty) + ts[ last ] = cf.And(guard[i], ts[ last ]); + res = cf.Or(cf.Block(body[i].pos, ts, defs.BOOLEAN_TYPE), res); + } + return res; + default: + throw new ApplicationError(); + } + return res; + } + + protected Tree toTree(PatternNode node, Tree selector) { + if (node == null) + return gen.mkBooleanLit(_m.pos, false); + switch (node) { + case DefaultPat(): + return toTree(node.and); + case ConstrPat(Symbol casted): + return make.If( + _m.pos, + cf.Is(selector, node.type), + cf.Block(selector.pos, + new Tree[]{ + make.ValDef(selector.pos, + //Kinds.VAL, + 0, + casted.name, + gen.mkType(selector.pos, node.type), + cf.As(selector, node.type)) + .setType(defs.UNIT_TYPE).setSymbol(casted), + toTree(node.and)}, defs.BOOLEAN_TYPE), + toTree(node.or, selector)).setType(defs.BOOLEAN_TYPE); + case ConstantPat( Object value ): + return make.If( + selector.pos, + cf.Equals(selector, + make.Literal(selector.pos, /*kind, */value) + .setType(node.type)), + toTree(node.and), + toTree(node.or, selector)).setType(defs.BOOLEAN_TYPE); + case VariablePat(Tree tree): + System.out.print("VariablePat"); + System.out.println( tree ); + return make.If( selector.pos, + cf.Equals(selector, tree), + toTree(node.and), + toTree(node.or, selector)).setType(defs.BOOLEAN_TYPE); + case SequencePat( _, _, _ ): + return callSequenceMatcher( node, + selector ); + default: + throw new ApplicationError(); + } + } + + /** 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 SequencePat( _, _, _ ): + 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? + make.If(selector.pos, + maybe cf.And( cf.Is(selector, seqpat.type()) + ... + */ + + // translate the _.and subtree of this SequencePat + + Vector seqPatNodes = new Vector(); + Vector bodies = new Vector(); + + PatternNode defaultNode = collectSeqPats( node, + seqPatNodes, + bodies ); + + Tree defaultCase = toTree( defaultNode, selector ); + + SequenceMatcher wordRec = new SequenceMatcher(unit, infer); + + 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 ] = ((SequencePat) 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; + + //case BoundPat( Symbol var, PatternNode pat ): + + } + + /* // unused, but helps understanding + public PatternNode match(Tree pat, PatternNode target) { + // advance one step in pattern + PatternNode next = target.and; + // we are done (no match yet) + if (next == null) + return null; + // check if matched + switch (next) { + case Body(_, _, _): + return next; + case Header(_, _): + Header header = (Header)next; + // get pattern arguments + Tree[] patArgs = patternArgs(pat); + // get next pattern node + PatternNode patNode = patternNode(pat, header, null); + do { + next = header.or; + while (next != null) { + if (superPat(next, patNode) && + ((target = match(patArgs, next)) != null)) + return target; + else if (isDefaultPat(next)) + return next.and; + next = next.or; + } + header = header.next; + } while (header != null); + return null; + default: + throw new ApplicationError(); + } + } + + public PatternNode match(Tree[] pats, PatternNode target) { + for (int i = 0; i < pats.length; i++) + if ((target = match(pats[i], target)) == null) + return null; + return target; + } + */ + + +} diff --git a/sources/scalac/transformer/matching/Autom2Scala.java b/sources/scalac/transformer/matching/Autom2Scala.java index 5c1dcd2596..4d73d6aad1 100644 --- a/sources/scalac/transformer/matching/Autom2Scala.java +++ b/sources/scalac/transformer/matching/Autom2Scala.java @@ -177,7 +177,7 @@ public class Autom2Scala { return gen.ValDef( pos, sym, init ); /* Kinds.VAR, - new ModifierSet(), + 0, sym.name, gen.mkType(pos, defs.INT_TYPE), init) diff --git a/sources/scalac/transformer/matching/PatternMatcher.java b/sources/scalac/transformer/matching/PatternMatcher.java index bebab020f8..ec36c1dd5a 100644 --- a/sources/scalac/transformer/matching/PatternMatcher.java +++ b/sources/scalac/transformer/matching/PatternMatcher.java @@ -687,14 +687,6 @@ public class PatternMatcher extends PatternTool { toTree(node.and)}, defs.BOOLEAN_TYPE), toTree(node.or, selector.duplicate())).setType(defs.BOOLEAN_TYPE); case SequencePat(Symbol casted, int len, Tree tree): - //return callSequenceMatcher( node, selector ); - - if( TestRegTraverser.apply( tree ) ) - { - //System.err.println("calling sequence matcher"); - return callSequenceMatcher( node, selector ); - } - Symbol lenSym = casted.type().lookup(LENGTH_N); Tree t = make.Select(selector.pos, cf.As(selector.duplicate(), node.type), LENGTH_N); switch (typeOf(lenSym)) { diff --git a/sources/scalac/transformer/matching/TestRegTraverser.java b/sources/scalac/transformer/matching/TestRegTraverser.java index 050fcf931b..9991daf48a 100644 --- a/sources/scalac/transformer/matching/TestRegTraverser.java +++ b/sources/scalac/transformer/matching/TestRegTraverser.java @@ -8,7 +8,7 @@ import scalac.ast.Traverser ; import Tree.Ident; import Tree.Bind; - class TestRegTraverser extends Traverser { +public class TestRegTraverser extends Traverser { boolean result; @@ -28,7 +28,7 @@ import Tree.Bind; } } - static boolean apply( Tree t ) { + public static boolean apply( Tree t ) { TestRegTraverser trt = new TestRegTraverser(); trt.traverse( t ); //System.err.println("TestRegTraverser says "+t+" -> "+trt.result); |