Project

General

Profile

root / trunk / compiler / ooasCompiler / src / org / momut / ooas / ast / types / Type.java @ 9

1
/**
2
  *
3
  *                      OOAS Compiler
4
  *
5
  *       Copyright 2015, AIT Austrian Institute of Technology.
6
  * This code is based on the C# Version of the OOAS Compiler, which is
7
  * copyright 2015 by the Institute of Software Technology, Graz University
8
  * of Technology with portions copyright by the AIT Austrian Institute of
9
  * Technology. All rights reserved.
10
  *
11
  * SEE THE "LICENSE" FILE FOR THE TERMS UNDER WHICH THIS FILE IS PROVIDED.
12
  *
13
  * If you modify the file please update the list of contributors below to in-
14
  * clude your name. Please also stick to the coding convention of using TABs
15
  * to do the basic (block-level) indentation and spaces for anything after
16
  * that. (Enable the display of special chars and it should be pretty obvious
17
  * what this means.) Also, remove all trailing whitespace.
18
  *
19
  * Contributors:
20
  *               Willibald Krenn (AIT)
21
  *               Stephan Zimmerer (AIT)
22
  *               Markus Demetz (AIT)
23
  *               Christoph Czurda (AIT)
24
  *
25
  */
26

    
27

    
28
package org.momut.ooas.ast.types;
29

    
30
import java.util.Iterator;
31

    
32
import org.momut.ooas.ast.AstNode;
33
import org.momut.ooas.ast.AstNodeTypeEnum;
34
import org.momut.ooas.ast.IAst;
35
import org.momut.ooas.ast.IAstVisitor;
36
import org.momut.ooas.ast.identifiers.TypeIdentifier;
37
import org.momut.ooas.utils.exceptions.ArgumentException;
38
import org.momut.ooas.utils.exceptions.NotImplementedException;
39
import org.momut.ooas.utils.exceptions.OoasCompilerRuntimeException;
40

    
41
public abstract class Type extends AstNode implements IAst
42
{
43
        private String m_origAnonName;
44
        protected TypeKind m_kind;
45
        protected TypeIdentifier m_identifier;
46
        protected int m_hash;
47
        //    protected long TimeStamp = DateTime.Now.Ticks;
48

    
49

    
50
        public TypeKind kind() { return m_kind; }
51

    
52
        public TypeIdentifier identifier() {
53
                synchronized(this) {
54
                        if (m_identifier == null)
55
                                SetupAnonymousName();
56
                }
57
                return m_identifier;
58
        }
59

    
60
        public boolean isAnonymousType() {
61
                final String anonName = AnonymousName();
62
                if (!m_origAnonName.equals(anonName))
63
                        throw new OoasCompilerRuntimeException("Internal Error: Anonymous Name changed from '%s' to '%s'.", m_origAnonName, anonName);
64
                return anonName.equals(m_identifier.tokenText());
65
        }
66

    
67
        protected Type(TypeKind aKind, TypeIdentifier anIdentifier)
68
        {
69
                m_kind = aKind;
70
                m_identifier = anIdentifier;
71
                m_hash = aKind.toString().hashCode(); //Enum.GetName(typeof(TypeKind), aKind).GetHashCode();
72
        }
73

    
74
        @Override
75
        public String toString()
76
        {
77
                return identifier().tokenText();
78
        }
79

    
80
        public /*virtual*/ String AnonymousName()
81
        {
82
                throw new NotImplementedException();
83
        }
84

    
85

    
86
        public void SetTypeIdentifier(TypeIdentifier anId)
87
        {
88
                m_identifier = anId;
89
        }
90

    
91
        public void SetupAnonymousName()
92
        {
93
                if (m_identifier == null)
94
                {
95
                        final String anonymousName = this.AnonymousName();
96
                        m_identifier = new TypeIdentifier(anonymousName, this, null);
97
                        m_origAnonName = anonymousName;
98
                }
99
        }
100

    
101

    
102
        @Override
103
        public AstNodeTypeEnum nodeType() { return AstNodeTypeEnum.type; }
104

    
105
        @Override
106
        public void Accept(IAstVisitor visitor)
107
        {
108
                throw new NotImplementedException();
109
        }
110

    
111

    
112

    
113
        public boolean IsNumeric()
114
        {
115
                final Object o = this;
116
                return (m_kind == TypeKind.IntType) ||
117
                                (m_kind == TypeKind.FloatType) ||
118
                                (m_kind == TypeKind.EnumeratedType && o instanceof ValuedEnumType);
119
        }
120

    
121
        public boolean IsQualitative()
122
        {
123
                return (m_kind == TypeKind.QrType);
124
        }
125

    
126
        /**
127
         * returns the number of unique values of the type (2 for bool, etc..)
128
         */
129
        public int valueCount() {
130
                throw new NotImplementedException(); // must be overridden by child
131
        }
132

    
133
        public static String High(Type atype)
134
        {
135
                switch (atype.kind())
136
                {
137
                        case BoolType:
138
                                return "1";
139
                        case EnumeratedType:
140
                                return Integer.toString((((EnumType)atype).listOfEnumSymbols().size() - 1));
141
                        case IntType:
142
                                return Integer.toString(((IntType)atype).rangeHigh());
143
                        case FloatType:
144
                                return Double.toString(((FloatType)atype).high());
145
                        default:
146
                                throw new NotImplementedException();
147
                }
148
        }
149

    
150
        public static String Low(Type atype)
151
        {
152
                switch (atype.kind())
153
                {
154
                        case BoolType:
155
                                return "0";
156
                        case EnumeratedType:
157
                                return "0";
158
                        case IntType:
159
                                return Integer.toString(((IntType)atype).rangeLow());
160
                        case FloatType:
161
                                return Double.toString(((FloatType)atype).low());
162
//                        case TypeKind.QrType:
163
//                                return "0";
164
                        default:
165
                                throw new NotImplementedException();
166
                }
167
        }
168

    
169

    
170
        /// <summary>
171
        ///  Returns a cover for two types (if possible).
172
        ///  note the cover type for two ints, floats, etc. will have max/min values
173
        ///  that reflect the maximum of the two operands.
174
        /// </summary>
175

    
176
        public static Type CoverType(Type type1, Type type2)
177
        {
178
                /*first some sanity checks*/
179
                if (type1 == null)
180
                        throw new ArgumentException("type1 null");
181
                if (type2 == null)
182
                        throw new ArgumentException("type2 null");
183

    
184
                if (type1.kind() == TypeKind.OpaqueType)
185
                        throw new ArgumentException("type1 opaque type");
186
                if (type2.kind() == TypeKind.OpaqueType)
187
                        throw new ArgumentException("type2 opaque type");
188

    
189
                if (type1 == type2)
190
                        return type1;
191
                if (Type.TypeEqual(type1, type2))
192
                        return type1;
193

    
194
                final TypeKind tk1 = type1.kind();
195
                final TypeKind tk2 = type2.kind();
196

    
197

    
198

    
199
                if (tk1 != tk2)
200
                {
201
                        // the only notion we support here is int->float and valenum -> int
202
                        if ((tk1 == TypeKind.IntType || tk2 == TypeKind.IntType)
203
                                        && (tk1 == TypeKind.FloatType || tk2 == TypeKind.FloatType))
204
                        {
205
                                final IntType aInt = tk1 == TypeKind.IntType ? (IntType)type1 : (IntType)type2;
206
                                final FloatType aFloat = tk1 == TypeKind.IntType ? (FloatType)type2 : (FloatType)type1;
207

    
208
                                final double low = aInt.rangeLow() < aFloat.low() ? (double)aInt.rangeLow() : aFloat.low();
209
                                final double high = aInt.rangeHigh() < aFloat.high() ? aFloat.high() : (double)aInt.rangeHigh();
210
                                final double precision = aFloat.precision() > 1 ? 1.0 : aFloat.precision();
211

    
212
                                return new FloatType(low, high, precision, null);
213

    
214
                        }
215
                        else if ((tk1 == TypeKind.IntType || tk2 == TypeKind.IntType)
216
                                        && (tk1 == TypeKind.EnumeratedType || tk2 == TypeKind.EnumeratedType))
217
                        {
218
                                final IntType intt1 = tk1 == TypeKind.IntType ? (IntType)type1 : (IntType)type2;
219
                                final EnumType anEnum = tk1 == TypeKind.IntType ? (EnumType)type2 : (EnumType)type1;
220

    
221
                                if (anEnum instanceof ValuedEnumType)
222
                                {
223
                                        final IntType intt2 = ((ValuedEnumType)anEnum).getIntType();
224
                                        final int low = intt1.rangeLow() < intt2.rangeLow() ? intt1.rangeLow() : intt2.rangeLow();
225
                                        final int high = intt1.rangeHigh() > intt2.rangeHigh() ? intt1.rangeHigh() : intt2.rangeHigh();
226
                                        return new IntType(low, high, null);
227
                                }
228
                                else
229
                                        return null;
230
                        }
231
                        else if (tk1 == TypeKind.Any || tk2 == TypeKind.Any)
232
                        {
233
                                final AnyType freeVar = tk1 == TypeKind.Any ? (AnyType)type1 : (AnyType)type2;
234
                                final Type fixedType = tk1 == TypeKind.Any ? type2 : type1;
235
                                final Type newcover = freeVar.VariableIdentifier().type().kind() == TypeKind.Any
236
                                                ? fixedType : CoverType(fixedType, freeVar.VariableIdentifier().type());
237
                                freeVar.VariableIdentifier().SetType(newcover);
238
                                return newcover;
239
                        }
240
                        else if (tk1 == TypeKind.OoActionSystemType && tk2 == TypeKind.Null)
241
                        {
242
                                return type1;
243
                        }
244
                        else if (tk2 == TypeKind.OoActionSystemType && tk1 == TypeKind.Null)
245
                        {
246
                                return type2;
247
                        }
248

    
249
                        else
250
                                return null;
251
                }
252
                else
253
                {
254
                        switch (tk1)
255
                        {
256
                                case Any:
257
                                        return type1;
258

    
259
                                case IntType:
260
                                        final IntType intt1 = (IntType)type1;
261
                                        final IntType intt2 = (IntType)type2;
262
                                        final int low = intt1.rangeLow() < intt2.rangeLow() ? intt1.rangeLow() : intt2.rangeLow();
263
                                        final int high = intt1.rangeHigh() > intt2.rangeHigh() ? intt1.rangeHigh() : intt2.rangeHigh();
264
                                        return new IntType(low, high, null);
265
                                case BoolType:
266
                                        return type1;
267
                                case FloatType:
268
                                        final FloatType floatt1 = (FloatType)type1;
269
                                        final FloatType floatt2 = (FloatType)type2;
270
                                        final double flow = floatt1.low() < floatt2.low() ? floatt1.low() : floatt2.low();
271
                                        final double fhigh = floatt1.high() > floatt2.high() ? floatt1.high() : floatt2.high();
272
                                        final double fprec = floatt1.precision() < floatt2.precision() ? floatt1.precision() : floatt2.precision();
273
                                        return new FloatType(flow, fhigh, fprec, null);
274
                                case EnumeratedType:
275
                                        return null;
276
                                case ListType:
277
                                        final ListType listt1 = (ListType)type1;
278
                                        final ListType listt2 = (ListType)type2;
279
                                        int maxelems = listt1.maxNumberOfElements() > listt2.maxNumberOfElements() ?
280
                                                listt1.maxNumberOfElements() : listt2.maxNumberOfElements();
281
                                        // empty lists lack type, so take the other one
282
                                        if ((listt1.innerType().kind() == TypeKind.Null) && (listt2.innerType().kind() != TypeKind.Null))
283
                                                return listt2;
284
                                        else if ((listt2.innerType().kind() == TypeKind.Null) && (listt1.innerType().kind() != TypeKind.Null))
285
                                                return listt1;
286
                                        else if (listt1.innerType().kind() == TypeKind.Null && listt2.innerType().kind() == TypeKind.Null)
287
                                                return listt1;
288
                                        else
289
                                        {
290
                                                final Type subtype = Type.CoverType(listt1.innerType(), listt2.innerType());
291
                                                if (subtype != null)
292
                                                        return new ListType(subtype, maxelems, null);
293
                                                else
294
                                                        return null;
295
                                        }
296
                                case MapType:
297
                                        final MapType mapt1 = (MapType)type1;
298
                                        final MapType mapt2 = (MapType)type2;
299
                                        // empty maps lack type, so take the other one.
300
                                        if ((mapt1.fromType().kind() == TypeKind.Null && mapt1.toType().kind() == TypeKind.Null)
301
                                           && (mapt2.fromType().kind() != TypeKind.Null && mapt2.toType().kind() != TypeKind.Null))
302
                                                return mapt2;
303
                                        else if ((mapt2.fromType().kind() == TypeKind.Null && mapt2.toType().kind() == TypeKind.Null)
304
                                           && (mapt1.fromType().kind() != TypeKind.Null && mapt1.toType().kind() != TypeKind.Null))
305
                                                return mapt1;
306
                                        else if ((mapt2.fromType().kind() == TypeKind.Null && mapt2.toType().kind() == TypeKind.Null)
307
                                           && (mapt1.fromType().kind() == TypeKind.Null && mapt1.toType().kind() == TypeKind.Null))
308
                                                return mapt1;
309
                                        else
310
                                        {
311
                                                final Type sub1 = Type.CoverType(mapt1.fromType(), mapt2.fromType());
312
                                                final Type sub2 = Type.CoverType(mapt2.toType(), mapt2.toType());
313
                                                maxelems = mapt1.maxNumberOfElements() > mapt2.maxNumberOfElements() ?
314
                                                        mapt1.maxNumberOfElements() : mapt2.maxNumberOfElements();
315
                                                if (sub1 != null && sub2 != null)
316
                                                        return new MapType(sub1, sub2, maxelems, null);
317
                                                else
318
                                                        return null;
319
                                        }
320
                                case QrType:
321
                                        return null; /*if refs are equal, we do not reach this statement! see above..*/
322
                                case TupleType:
323
                                        final TupleType tuplet1 = (TupleType)type1;
324
                                        final TupleType tuplet2 = (TupleType)type2;
325
                                        final TupleType result = new TupleType(null);
326
                                        final Iterator<Type> innert1 = tuplet1.innerTypes().iterator();
327
                                        final Iterator<Type> innert2 = tuplet2.innerTypes().iterator();
328
                                        while (innert1.hasNext())
329
                                        {
330
                                                final Type newinner = Type.CoverType(innert1.next(), innert2.next());
331
                                                if (newinner == null)
332
                                                        return null;
333
                                                result.AddType(newinner);
334
                                        }
335
                                        return result;
336
                                case OoActionSystemType:
337
                                        if (type1.kind() == TypeKind.Null && type2.kind() != TypeKind.Null)
338
                                                return type2;
339
                                        else if (type2.kind() == TypeKind.Null && type1.kind() != TypeKind.Null)
340
                                                return type1;
341
                                        else if (type1.kind() == TypeKind.Null && type2.kind() == TypeKind.Null)
342
                                                return type2;
343
                                        else if (type1 == type2) // ref equals!
344
                                                return type1;
345
                                        else
346
                                                return ClassBaseType((OoActionSystemType)type1, (OoActionSystemType)type2);
347
                                case OpaqueType:
348
                                        assert(false);
349
                                        return null;
350
                                default:
351
                                        throw new NotImplementedException();
352
                        }
353
                }
354
        }
355

    
356
        private static Type ClassBaseType(OoActionSystemType type1, OoActionSystemType type2)
357
        {
358
                // this is rather inefficient.. should be done differently
359
                final OoActionSystemType typea = type1;
360
                final OoActionSystemType typeb = type2;
361
                OoActionSystemType basea = type1;
362
                OoActionSystemType baseb = type2;
363
                while (basea != null)
364
                {
365
                        if (basea == typeb)  // ref equals
366
                                return basea;
367
                        basea = basea.baseType();
368
                }
369
                while (baseb != null)
370
                {
371
                        if (baseb == typea) // ref equals
372
                                return baseb;
373
                        baseb = baseb.baseType();
374
                }
375
                return null;
376
        }
377

    
378
        public static boolean FirstTypeLessRange(Type type1, Type type2)
379
        {
380
                final TypeKind tk1 = type1.kind();
381
                final TypeKind tk2 = type2.kind();
382

    
383
                if (tk1 != tk2)
384
                        throw new ArgumentException("Types need to be equal");
385

    
386
                switch (tk1)
387
                {
388
                        case Any:
389
                                return false;
390
                        case IntType:
391
                                final IntType Int1 = (IntType)type1;
392
                                final IntType Int2 = (IntType)type2;
393
                                return Int1.rangeLow() > Int2.rangeLow() ||
394
                                        Int1.rangeHigh() < Int2.rangeHigh();
395
                        case BoolType:
396
                                return false;
397
                        case FloatType:
398
                                final FloatType Float1 = (FloatType)type1;
399
                                final FloatType Float2 = (FloatType)type2;
400
                                return Float1.low() > Float2.low()
401
                                        || Float1.high() < Float2.high()
402
                                        || Float1.precision() > Float2.precision();
403
                        case EnumeratedType:
404
                                return false;
405
                        case ListType:
406
                                final ListType listt1 = (ListType)type1;
407
                                final ListType listt2 = (ListType)type2;
408
                                return (listt1.maxNumberOfElements() < listt2.maxNumberOfElements()) ||
409
                                        Type.FirstTypeLessRange(listt1.innerType(), listt2.innerType());
410
                        case MapType:
411
                                final MapType mapt1 = (MapType)type1;
412
                                final MapType mapt2 = (MapType)type2;
413
                                return (mapt1.maxNumberOfElements() < mapt2.maxNumberOfElements()) ||
414
                                        Type.FirstTypeLessRange(mapt1.fromType(), mapt2.fromType()) ||
415
                                        Type.FirstTypeLessRange(mapt1.toType(), mapt2.toType());
416
                        case QrType:
417
                                return false;
418
                        case TupleType:
419
                                final TupleType tuplet1 = (TupleType)type1;
420
                                final TupleType tuplet2 = (TupleType)type2;
421
                                if (tuplet1.innerTypes().size() != tuplet2.innerTypes().size())
422
                                        return false;
423
                                final Iterator<Type> innert1 = tuplet1.innerTypes().iterator();
424
                                final Iterator<Type> innert2 = tuplet2.innerTypes().iterator();
425
                                while (innert1.hasNext())
426
                                {
427
                                        if (Type.FirstTypeLessRange(innert1.next(), innert2.next()))
428
                                                return true;
429
                                }
430
                                return false;
431
                        case OoActionSystemType:
432
                                return false;
433
                        case OpaqueType:
434
                                assert(false);
435
                                return false;
436
                        default:
437
                                throw new NotImplementedException();
438
                }
439
        }
440

    
441
        public static boolean TypeEqualByKind(Type type1, Type type2)
442
        {
443
                if ((type1 == null) || (type2 == null))
444
                        return false;
445

    
446
                final TypeKind tk1 = type1.kind();
447
                final TypeKind tk2 = type2.kind();
448

    
449
                // if of different kind, then return false..
450
                if (tk1 != tk2)
451
                        return false;
452

    
453
                // if same kind, make a rigorous check
454
                switch (tk1)
455
                {
456
                        case Any:
457
                                return true;
458

    
459
                        case IntType:
460
                        case BoolType:
461
                        case FloatType:
462
                                return true;
463
                        case EnumeratedType:
464
                                return type1 == type2; // ref equals
465
                        case ListType:
466
                                final ListType listt1 = (ListType)type1;
467
                                final ListType listt2 = (ListType)type2;
468
                                return Type.TypeEqualByKind(listt1.innerType(), listt2.innerType());
469
                        case MapType:
470
                                final MapType mapt1 = (MapType)type1;
471
                                final MapType mapt2 = (MapType)type2;
472
                                return Type.TypeEqualByKind(mapt1.fromType(), mapt2.fromType()) &&
473
                                        Type.TypeEqualByKind(mapt1.toType(), mapt2.toType());
474
                        case TupleType:
475
                                final TupleType tuplet1 = (TupleType)type1;
476
                                final TupleType tuplet2 = (TupleType)type2;
477
                                if (tuplet1.innerTypes().size() != tuplet2.innerTypes().size())
478
                                        return false;
479
                                final Iterator<Type> innert1 = tuplet1.innerTypes().iterator();
480
                                final Iterator<Type> innert2 = tuplet2.innerTypes().iterator();
481
                                while (innert1.hasNext())
482
                                {
483
                                        if (!Type.TypeEqualByKind(innert1.next(), innert2.next()))
484
                                                return false;
485
                                }
486
                                return true;
487
                        case OoActionSystemType:
488
                                return type1 == type2; // ref equ.
489
                        case OpaqueType:
490
                                assert(false);
491
                                return false;
492
                        default:
493
                                throw new NotImplementedException();
494
                }
495
        }
496

    
497

    
498
        public static boolean TypeEqual(Type type1, Type type2)
499
        {
500
                // this will also work with opaque types...
501
                while (type1 instanceof OpaqueType)
502
                        type1 = ((OpaqueType)type1).resolvedType();
503
                while (type2 instanceof OpaqueType)
504
                        type2 = ((OpaqueType)type2).resolvedType();
505

    
506
                if ((type1 == null) || (type2 == null))
507
                        return false;
508

    
509
                final TypeKind tk1 = type1.kind();
510
                final TypeKind tk2 = type2.kind();
511

    
512
                // if of different kind, then return false..
513
                if (tk1 != tk2)
514
                        return false;
515

    
516
                // if same kind, make a rigorous check
517
                switch (tk1)
518
                {
519
                        case IntType:
520
                                final IntType intt1 = (IntType)type1;
521
                                final IntType intt2 = (IntType)type2;
522
                                return intt1.rangeLow() == intt2.rangeLow() &&
523
                                        intt1.rangeHigh() == intt2.rangeHigh();
524
                        case BoolType:
525
                                return true;
526
                        case FloatType:
527
                                final FloatType floatt1 = (FloatType)type1;
528
                                final FloatType floatt2 = (FloatType)type2;
529
                                return floatt1.low() == floatt2.low() &&
530
                                        floatt1.high() == floatt2.high() &&
531
                                        floatt1.precision() == floatt2.precision();
532
                        case EnumeratedType:
533
                                return type1 == type2; // ref equ
534
                        case ListType:
535
                                final ListType listt1 = (ListType)type1;
536
                                final ListType listt2 = (ListType)type2;
537
                                // an empty list can be of any type..
538
                                /*if ((listt1.innerType.kind == TypeKind.Null) || (listt2.innerType.kind == TypeKind.Null))
539
                                        return true;
540
                                else*/
541
                                return Type.TypeEqual(listt1.innerType(), listt2.innerType()) &&
542
                                                listt1.maxNumberOfElements() == listt2.maxNumberOfElements(); // need this because of covertype
543
                        case MapType:
544
                                final MapType mapt1 = (MapType)type1;
545
                                final MapType mapt2 = (MapType)type2;
546
                                return Type.TypeEqual(mapt1.fromType(), mapt2.fromType()) &&
547
                                        Type.TypeEqual(mapt1.toType(), mapt2.toType()) &&
548
                                        mapt1.maxNumberOfElements() == mapt2.maxNumberOfElements(); // need this because of covertype
549
                        case TupleType:
550
                                final TupleType tuplet1 = (TupleType)type1;
551
                                final TupleType tuplet2 = (TupleType)type2;
552
                                if (tuplet1.innerTypes().size() != tuplet2.innerTypes().size())
553
                                        return false;
554
                                final Iterator<Type> innert1 = tuplet1.innerTypes().iterator();
555
                                final Iterator<Type> innert2 = tuplet2.innerTypes().iterator();
556
                                while (innert1.hasNext())
557
                                {
558
                                        if (!Type.TypeEqual(innert1.next(), innert2.next()))
559
                                                return false;
560
                                }
561
                                return true;
562
                        case OoActionSystemType:
563
                                return type1 == type2; // ref equ. // || Covariance((OoActionSystemType)type1, (OoActionSystemType)type2);
564
                        case OpaqueType:
565
                                assert(false);
566
                                return false;
567
                        case Null:
568
                        case Any:
569
                                return true;
570
                        default:
571
                                throw new NotImplementedException();
572
                }
573
        }
574

    
575
        /// <summary>
576
        /// checks if type 2 is a desc. of type 1
577
        /// </summary>
578
        public static boolean Covariance(OoActionSystemType ooActionSystemType, OoActionSystemType ooActionSystemType_2)
579
        {
580
                // check if type 2 is a desc. of type 1
581
                while (ooActionSystemType != ooActionSystemType_2 && ooActionSystemType_2.baseType() != null) // ref equ.
582
                        ooActionSystemType_2 = ooActionSystemType_2.baseType();
583

    
584
                return ooActionSystemType == ooActionSystemType_2; // ref equ.
585
        }
586
}