/* ____ ____ ____ ____ ______ *\ ** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** ** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** ** /_____/\____/\___/\____/____/ ** ** ** ** $Id$ \* */ package scalac.transformer.matching; import ch.epfl.lamp.util.Position; import scalac.*; import scalac.ast.*; import scalac.util.*; import scalac.symtab.*; import scalac.typechecker.*; import PatternNode.*; import Tree.*; class CodeFactory extends PatternTool { private int pos = Position.FIRSTPOS ; static final Name HEAD_N = Name.fromString("head"); static final Name TAIL_N = Name.fromString("tail"); static final Name SEQ_TRACE_N = Name.fromString("scala.SeqTrace"); static final Name HEADSTATE_N = Name.fromString("headState"); static final Name HEADELEM_N = Name.fromString("headElem"); static final Name ISEMPTY_N = Name.fromString("isEmpty"); Symbol refSym() { // delete Names.Ref return defs.getType( Names.scala_Ref ).symbol() ; } Symbol seqSym() { return defs.getType( Names.scala_Seq ).symbol() ; } Symbol iteratorSym() { return defs.getType( Names.scala_Iterator ).symbol() ; } Symbol seqListSym() { return defs.getType( Names.scala_List ).symbol() ; } Symbol seqConsSym() { return defs.getType( Names.scala_COLONCOLON ).symbol() ; } Symbol seqNilSym() { return defs.getType( Names.scala_Nil ).symbol(); // no need for TypeApply anymore!x } Symbol seqIterSym() { return defs.getType( Names.scala_Iterator ).symbol(); } Symbol seqIterSym_next() { Scope scp = seqIterSym().members(); return scp.lookup( Names.next ); } Symbol seqIterSym_hasNext() { Scope scp = seqIterSym().members(); return scp.lookup( Names.hasNext ); } Symbol seqTraceSym() { return defs.getType( Name.fromString( "scala.SeqTrace" ) ).symbol(); } Symbol seqTraceConsSym() { return defs.getType( Name.fromString( "scala.SeqTraceCons" ) ).symbol(); } Symbol seqTraceNilSym() { return defs.getType( Name.fromString( "scala.SeqTraceNil" ) ).symbol(); } Symbol iterableSym() { return defs.getType( Names.scala_Iterable ).symbol(); } Symbol newIterSym() { Scope scp = iterableSym().members(); return scp.lookup( Names.elements ); } public CodeFactory( Unit unit, Infer infer ) { super( unit, infer ); } // --------- these are new /** If ... pos, type is copied from thenBody */ Tree If( Tree cond, Tree thenBody, Tree elseBody ) { //assert( thenBody.type().equals( elseBody.type() ) // || thenBody.type().isSubType( elseBody.type() ) // /*|| elseBody.type().isSubType( thenBody.type() BUG */) // : "you try to construct a naughty if " // + "thenBody: "+thenBody.type+" elseBody:"+elseBody.type; assert cond != null:"cond is null"; assert thenBody != null:"thenBody is null"; assert elseBody != null:"elseBody is null"; return make.If( thenBody.pos, cond, thenBody, elseBody ).setType( elseBody.type() ); } Tree Switch( Tree selector, Tree condition[], Tree body[], Tree defaultBody ) { assert selector != null:"selector is null"; assert condition != null:"cond is null"; assert body != null:"body is null"; assert defaultBody != null:"defaultBody is null"; Tree result = defaultBody; for( int i = condition.length-1; i >= 0; i-- ) result = If( condition[ i ], body[ i ], result ).setType( result.type ); return result ; } /** returns `List[ elemType ]' */ Type SeqListType( Type elemType ) { return Type.TypeRef( defs.SCALA_TYPE, seqListSym(), new Type[] { elemType }); } /** returns `SeqTrace[ elemType ]' */ Type SeqTraceType( Type elemType ) { return Type.TypeRef( defs.SCALA_TYPE, seqTraceSym(), new Type[] { elemType }); } /** returns `Iterator[ elemType ]' */ Type _seqIterType( Type elemType ) { Symbol seqIterSym = defs.getType( Names.scala_Iterator ).symbol(); return Type.TypeRef( defs.SCALA_TYPE, seqIterSym(), new Type[] { elemType }); } /** returns `' */ Tree newIterator( Tree seqObj, Type elemType ) { Symbol newIterSym = newIterSym(); Tree t1 = gen.Select( Position.FIRSTPOS, seqObj, newIterSym) .setType( Type.MethodType(new Symbol[] {},_seqIterType( elemType ))); Tree theIterator = gen.Apply(seqObj.pos, t1, Tree.EMPTY_ARRAY) .setType( _seqIterType( elemType ) ); return theIterator; } /** returns code `.elements' * the parameter needs to have type attribute `Sequence[]' */ Tree newIterator( Tree seqObj ) { return newIterator( seqObj, getElemType_Sequence( seqObj.type() )); } /** FIXME - short type */ Tree ignoreValue( Type asType ) { if( asType.isSameAs(defs.BYTE_TYPE )) return make.Literal(Position.FIRSTPOS, new Integer( 0 )) .setType( defs.INT_TYPE ); else if( asType.isSameAs( defs.CHAR_TYPE )) return make.Literal(Position.FIRSTPOS, new Character( 'a' )) .setType( defs.CHAR_TYPE ); else if( asType.isSameAs(defs.SHORT_TYPE )) return make.Literal(Position.FIRSTPOS, new Integer/*Short?*/( 0 )) .setType( defs.SHORT_TYPE ); else if( asType.isSameAs(defs.INT_TYPE )) return Int( 0 ); else if( asType.isSameAs(defs.LONG_TYPE )) return make.Literal(Position.FIRSTPOS, new Long( 0 )) .setType( defs.LONG_TYPE ); else if( asType.isSameAs(defs.FLOAT_TYPE )) return make.Literal(Position.FIRSTPOS, new Float( 0 )) .setType( defs.FLOAT_TYPE ); else if( asType.isSameAs(defs.DOUBLE_TYPE )) return make.Literal(Position.FIRSTPOS, new Double( 0 )) .setType( defs.DOUBLE_TYPE ); else if( asType.isSameAs(defs.BOOLEAN_TYPE )) return gen.mkBooleanLit(Position.FIRSTPOS, false); else if( asType.isSameAs(defs.STRING_TYPE )) return make.Literal(Position.FIRSTPOS, "") .setType( defs.STRING_TYPE ); /** FIX ME FOR THE NEW VERSION*/ else return /*gen.Apply( */Null( asType )/*, Tree.EMPTY_ARRAY)*/; //throw new ApplicationError("don't know how to handle "+asType); } /** FIX ME FOR THE NEW VERSION */ Tree Null( Type asType ) { return gen.Ident(pos, defs.NULL );/*gen.TypeApply(pos, gen.Ident(pos, defs.NULL ), new Tree[] { gen.mkType(pos, asType) } );*/ } // the caller needs to set the type ! Tree _applyNone( Tree arg ) { return make.Apply(Position.FIRSTPOS, arg, Tree.EMPTY_ARRAY ); } /** code `new SeqTraceNil[ elemType ]()' */ Tree _seqTraceNil( Type elemType ) { assert elemType != null : "elemType = null??"; return gen.New( Position.FIRSTPOS, defs.SCALA_TYPE, seqTraceNilSym(), new Type[] { elemType }, new Tree[] {}); } /** creates an scala.Int constant */ Tree Int( int val ) { return Int( new Integer( val )); } Tree Int( Integer valI ) { return make.Literal( Position.FIRSTPOS, valI ) .setType( defs.INT_TYPE ); } /** code `new SeqTraceCons[ elemType ]( state, head, tail )' */ Tree newSeqTraceCons( Integer state, Tree head, Tree tail ) { assert head != null : "head null"; assert tail != null : "tail null"; assert state != null : "state null"; return gen.New( Position.FIRSTPOS, defs.SCALA_TYPE, seqTraceConsSym(), new Type[] { head.type() }, new Tree[] { Int( state ), head, tail }); } /* Type _seqTraceConsType( Type elemType ) { return Type.TypeRef( defs.SCALA_TYPE, seqTraceConsSym, new Type[] { elemType }); } */ // `SeqCons[ elemType ]' Type _seqConsType( Type elemType ) { return Type.TypeRef( defs.SCALA_TYPE, seqConsSym(), new Type[] { elemType }); } Tree newSeqNil( Type tpe ) { /* assert tpe != null :"tpe = null !?"; return gen.New( Position.FIRSTPOS, defs.SCALA_TYPE, seqNilSym(), new Type[] { tpe }, new Tree[] {}); */ return gen.Select(gen.Ident(Position.FIRSTPOS, defs.SCALA), Names.Nil/*seqNilSym()*/); } // EXPERIMENTAL Tree newRef( Tree init ) { //System.out.println( "hello:"+refSym().type() ); return gen.New( Position.FIRSTPOS, defs.SCALA_TYPE, refSym(), new Type[] { init.type() }, new Tree[] { init } ); /* return gen.Apply( gen.TypeApply(Position.FIRSTPOS, gen.Select(gen.Ident(Position.FIRSTPOS, defs.SCALA), Names.Ref), new Tree[] { gen.mkType(Position.FIRSTPOS, init.type() ) } ), new Tree[] { init } ); */ } Tree newSeqCons( Tree head, Tree tail ) { return gen.New( Position.FIRSTPOS, defs.SCALA_TYPE, seqConsSym(), new Type[] { head.type() }, new Tree[] { head, tail }); } /** returns A for T <: Sequence[ A ] */ Type getElemType_Sequence( Type tpe ) { //System.err.println("getElemType_Sequence("+tpe.widen()+")"); Type tpe1 = tpe.widen().baseType( seqSym() ); if( tpe1 == Type.NoType ) throw new ApplicationError("arg "+tpe+" not subtype of Sequence[ A ]"); return tpe1.typeArgs()[ 0 ]; } /** returns A for T <: Iterator[ A ] */ Type getElemType_Iterator( Type tpe ) { //System.err.println("getElemType_Iterator("+tpe+")"); Type tpe1 = tpe.widen().baseType( iteratorSym() ); switch( tpe1 ) { case TypeRef(_,_,Type[] args): return args[ 0 ]; default: throw new ApplicationError("arg "+tpe+" not subtype of Iterator[ A ]"); } } /** `it.next()' */ public Tree _next( Tree iter ) { Type elemType = getElemType_Iterator( iter.type() ); Symbol nextSym = seqIterSym_next(); return _applyNone( gen.Select( iter, nextSym )).setType( elemType ); } /** `it.hasNext()' */ public Tree _hasNext( Tree iter ) { Symbol hasNextSym = seqIterSym_hasNext(); return _applyNone( gen.Select( iter, hasNextSym )).setType( defs.BOOLEAN_TYPE ); } /** `!it.hasCur()' */ public Tree _not_hasNext( Tree iter ) { return _applyNone( gen.Select( _hasNext( iter ), notSym )) .setType( defs.BOOLEAN_TYPE ); } /** `trace.isEmpty' */ public Tree isEmpty( Tree iter ) { Scope scp = seqTraceSym().members(); Symbol isEmptySym = scp.lookup ( ISEMPTY_N ); return _applyNone( gen.Select( iter, isEmptySym )) .setType( defs.BOOLEAN_TYPE ); } Tree SeqTrace_headElem( Tree arg ) { Scope scp = seqTraceSym().members(); Symbol headSym = scp.lookup ( HEADELEM_N ); assert headSym != Symbol.NONE; return gen.Apply( gen.Select( pos, arg, headSym ), Tree.EMPTY_ARRAY ); } Tree SeqTrace_headState( Tree arg ) { Scope scp = seqTraceSym().members(); Symbol headSym = scp.lookup ( HEADSTATE_N ); assert headSym != Symbol.NONE; return gen.Apply( gen.Select( pos, arg, headSym ), Tree.EMPTY_ARRAY ); } Tree SeqTrace_tail( Tree arg ) { Scope scp = seqTraceSym().members(); Symbol tailSym = scp.lookup ( TAIL_N ); assert tailSym != Symbol.NONE; return gen.Apply( gen.Select( pos, arg, tailSym ), Tree.EMPTY_ARRAY ); } /** `.head()' */ Tree SeqList_head( Tree arg ) { Scope scp = seqListSym().members(); Symbol headSym = scp.lookup ( HEAD_N ); assert headSym != Symbol.NONE; return gen.Apply( make.Select( pos, arg, HEAD_N ) .setType( headSym.type() ) .setSymbol( headSym ), Tree.EMPTY_ARRAY); } /** return the analyzed type */ public Type typeOf(Symbol sym) { return sym.type(); //return sym.typeAt(unit.global.ANALYZER_PHASE.id); } /** return the analyzed type */ public Type typeOf0(Symbol sym) { return sym.typeAt(unit.global.PHASE.ANALYZER.id); } protected Tree Block(int pos, Tree[] ts, Type tpe) { if (ts.length == 1) return ts[0]; else if (ts.length > 1) switch (ts[ts.length - 1]) { case Block(Tree[] ts0): Tree[] ts1 = new Tree[ts0.length + ts.length - 1]; System.arraycopy(ts, 0, ts1, 0, ts.length - 1); System.arraycopy(ts0, 0, ts1, ts.length - 1, ts0.length); return Block(pos, ts1, tpe); } return make.Block(pos, ts).setType(tpe); } // unused public Tree Negate(Tree tree) { switch (tree) { case Literal(Object value): return gen.mkBooleanLit(tree.pos, !((Boolean)value).booleanValue()); } return make.Apply( tree.pos, gen.Select(tree, NOT_N), Tree.EMPTY_ARRAY).setType(defs.BOOLEAN_TYPE); } protected Tree And(Tree left, Tree right) { switch (left) { case Literal(Object value): return ((Boolean)value).booleanValue() ? right : left; } switch (right) { case Literal(Object value): if (((Boolean)value).booleanValue()) return left; } Symbol fun = left.type.lookup(AND_N); return make.Apply( left.pos, make.Select( left.pos, left, AND_N).setType(typeOf(fun)).setSymbol(fun), new Tree[]{right}).setType(defs.BOOLEAN_TYPE); } protected Tree Or(Tree left, Tree right) { switch (left) { case Literal(Object value): return ((Boolean)value).booleanValue() ? left : right; } switch (right) { case Literal(Object value): if (!((Boolean)value).booleanValue()) return left; } Symbol fun = left.type.lookup(OR_N); return make.Apply( left.pos, make.Select( left.pos, left, OR_N).setType(typeOf(fun)).setSymbol(fun), new Tree[]{right}).setType(defs.BOOLEAN_TYPE); } protected Tree Is(Tree tree, Type type) { return make.Apply( tree.pos, make.TypeApply( tree.pos, make.Select( tree.pos, tree, defs.IS.name).setType(typeOf(defs.IS)).setSymbol(defs.IS), new Tree[]{gen.mkType(tree.pos, type)}) .setType(Type.MethodType(Symbol.EMPTY_ARRAY, defs.BOOLEAN_TYPE)), Tree.EMPTY_ARRAY).setType(defs.BOOLEAN_TYPE); } protected Tree As(Tree tree, Type type) { return make.Apply( tree.pos, make.TypeApply( tree.pos, make.Select( tree.pos, tree, defs.AS.name).setType(typeOf(defs.AS)).setSymbol(defs.AS), new Tree[]{gen.mkType(tree.pos, type)}) .setType(Type.MethodType(Symbol.EMPTY_ARRAY, type)), Tree.EMPTY_ARRAY).setType(type); } protected Tree Equals(Tree left, Tree right) { Symbol fun = left.type.lookup(EQUALS_N); switch (typeOf(fun)) { case OverloadedType(Symbol[] alts, Type[] alttypes): //System.out.println("**** " + left.type); Tree t = make.Select(left.pos, left, EQUALS_N); //for (int i = 0; i < alttypes.length; i++) // System.out.println(alts[i] + ": " + alttypes[i]); infer.methodAlternative(t, alts, alttypes, new Type[]{right.type}, defs.BOOLEAN_TYPE); return make.Apply(left.pos, t, new Tree[]{right}).setType(defs.BOOLEAN_TYPE); default: //System.out.println("#### " + left.type + ": " + fun); return make.Apply( left.pos, make.Select( left.pos, left, EQUALS_N).setType(typeOf(fun)).setSymbol(fun), new Tree[]{right}).setType(defs.BOOLEAN_TYPE); } } protected Tree ThrowMatchError(int pos, Type type) { Symbol matchErrorModule = defs.SCALA.members().lookup(MATCHERROR_N); outer: switch (typeOf(matchErrorModule)) { case OverloadedType(Symbol[] alts, Type[] alttypes): for (int i = 0; i < alts.length; i++) switch (alttypes[i]) { case TypeRef(_, _, _): matchErrorModule = alts[i]; break outer; } } Symbol failMethod = typeOf(matchErrorModule).lookup(FAIL_N); return make.Apply( pos, make.TypeApply( pos, make.Select( pos, make.Select( pos, make.Ident(pos, Names.scala).setType(typeOf(defs.SCALA)).setSymbol(defs.SCALA), MATCHERROR_N) .setSymbol(matchErrorModule) .setType(typeOf(matchErrorModule)), FAIL_N).setType(typeOf(failMethod)).setSymbol(failMethod), new Tree[]{gen.mkType(pos, type)}) .setType(((Type.PolyType) typeOf(failMethod)).result.subst( typeOf(failMethod).typeParams(), new Type[]{type})), new Tree[]{ make.Literal(pos, unit.toString()).setType(defs.STRING_TYPE), make.Literal(pos, new Integer(Position.line(pos))).setType(defs.INT_TYPE) }).setType(type); } }