summaryrefslogtreecommitdiff
path: root/sources/scalac/transformer/matching/CodeFactory.java
blob: 425fd4c9acdeddd869fe684abd91bd46bd16781f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
/*     ____ ____  ____ ____  ______                                     *\
**    / __// __ \/ __// __ \/ ____/    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 `<seqObj.elements>' */
    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 `<seqObj>.elements'
     *  the parameter needs to have type attribute `Sequence[<elemType>]'
     */
    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 );
      }

      /** `<seqlist>.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);
    }

}