Exemple #1
0
 protected FunctionType(ExprType ret_t, List <Utils.StoreEntry> args, Boolean is_varargs)
     : base(true, false)
 {
     this.Args       = args;
     this.ReturnType = ret_t;
     this.HasVarArgs = is_varargs;
 }
Exemple #2
0
            public void DefineStruct(IReadOnlyList <Tuple <String, ExprType> > attribs)
            {
                if (this.IsComplete)
                {
                    throw new InvalidOperationException("Cannot redefine a struct.");
                }

                this._attribs = new List <Utils.StoreEntry>();
                Int32 offset           = 0;
                Int32 struct_alignment = 0;

                foreach (Tuple <String, ExprType> attrib in attribs)
                {
                    String   name = attrib.Item1;
                    ExprType type = attrib.Item2;

                    Int32 attrib_alignment = type.Alignment;

                    // All attributes must be aligned.
                    // This means that the alignment of the struct is the largest attribute alignment.
                    struct_alignment = Math.Max(struct_alignment, attrib_alignment);

                    // Make sure all attributes are put into aligned places.
                    offset = Utils.RoundUp(offset, attrib_alignment);

                    this._attribs.Add(new Utils.StoreEntry(name, type, offset));

                    offset += type.SizeOf;
                }

                this._size_of = Utils.RoundUp(offset, struct_alignment);
            }
Exemple #3
0
 public Decln(String name, StorageClass scs, ExprType type, Option <Initr> initr)
 {
     this.name  = name;
     this.scs   = scs;
     this.type  = type;
     this.initr = initr;
 }
Exemple #4
0
        public override void CGenStmt(Env env, CGenState state)
        {
            ExprType ret_type = env.GetCurrentFunction().ReturnType;

            Int32 stack_size = state.StackSize;

            if (this.ExprOpt.IsSome)
            {
                // Evaluate the Value.
                this.ExprOpt.Value.CGenValue(state);

                // If the function returns a struct, copy it to the address given by 8(%ebp).
                if (this.ExprOpt.Value.Type is StructOrUnionType)
                {
                    state.MOVL(Reg.EAX, Reg.ESI);
                    state.MOVL(2 * ExprType.SIZEOF_POINTER, Reg.EBP, Reg.EDI);
                    state.MOVL(this.ExprOpt.Value.Type.SizeOf, Reg.ECX);
                    state.CGenMemCpy();
                    state.MOVL(2 * ExprType.SIZEOF_POINTER, Reg.EBP, Reg.EAX);
                }

                // Restore stack size.
                state.CGenForceStackSizeTo(stack_size);
            }
            // Jump to end of the function.
            state.JMP(state.ReturnLabel);
        }
Exemple #5
0
        /// <summary>
        /// <para>Perform the usual arithmetic conversion on two expressions.</para>
        /// <para>If either expression is <see cref="DoubleType"/>, then both are converted to <see cref="DoubleType"/>.</para>
        /// <para>Else, if either expression is <see cref="FloatType"/>, then both are converted to <see cref="FloatType"/>.</para>
        /// <para>Else, if either expression is <see cref="ULongType"/>, then both are converted to <see cref="ULongType"/>.</para>
        /// <para>Else, both are converted to <see cref="LongType"/>.</para>
        /// </summary>
        /// <param name="e1">The first expression to be casted. Must have <see cref="ArithmeticType"/>.</param>
        /// <param name="e2">The second expression to be casted. Must have <see cref="ArithmeticType"/>.</param>
        /// <returns>
        /// The two casted expressions, and an <see cref="ExprTypeKind"/>.
        /// </returns>
        public static Tuple <Expr, Expr, ExprTypeKind> UsualArithmeticConversion(Expr e1, Expr e2)
        {
            ExprType t1 = e1.Type;
            ExprType t2 = e2.Type;

            Boolean c1 = t1.IsConst;
            Boolean v1 = t1.IsVolatile;
            Boolean c2 = t2.IsConst;
            Boolean v2 = t2.IsVolatile;

            // 1. if either Expr is double: both are converted to double
            if (t1.Kind == ExprTypeKind.DOUBLE || t2.Kind == ExprTypeKind.DOUBLE)
            {
                return(new Tuple <Expr, Expr, ExprTypeKind>(MakeCast(e1, new DoubleType(c1, v1)), MakeCast(e2, new DoubleType(c2, v2)), ExprTypeKind.DOUBLE));
            }

            // 2. if either Expr is float: both are converted to float
            if (t1.Kind == ExprTypeKind.FLOAT || t2.Kind == ExprTypeKind.FLOAT)
            {
                return(new Tuple <Expr, Expr, ExprTypeKind>(MakeCast(e1, new FloatType(c1, v1)), MakeCast(e2, new FloatType(c2, v2)), ExprTypeKind.FLOAT));
            }

            // 3. if either Expr is unsigned long: both are converted to unsigned long
            if (t1.Kind == ExprTypeKind.ULONG || t2.Kind == ExprTypeKind.ULONG)
            {
                return(new Tuple <Expr, Expr, ExprTypeKind>(MakeCast(e1, new ULongType(c1, v1)), MakeCast(e2, new ULongType(c2, v2)), ExprTypeKind.ULONG));
            }

            // 4. both are converted to long
            return(new Tuple <Expr, Expr, ExprTypeKind>(MakeCast(e1, new LongType(c1, v1)), MakeCast(e2, new LongType(c2, v2)), ExprTypeKind.LONG));
        }
Exemple #6
0
 public ConditionalExpr(Expr cond, Expr trueExpr, Expr falseExpr, ExprType type)
 {
     this.Cond      = cond;
     this.TrueExpr  = trueExpr;
     this.FalseExpr = falseExpr;
     this.Type      = type;
 }
Exemple #7
0
 private TypeCast(TypeCastType kind, Expr expr, ExprType type, Env env)
 {
     this.Expr = expr;
     this.Kind = kind;
     this.Type = type;
     this.Env  = env;
 }
Exemple #8
0
            // PushEnum
            // ========
            // input: name, Type
            // output: Environment
            // return a new environment which adds a enum Value
            //
            public Scope PushEnum(String name, ExprType type, Int32 value)
            {
                Scope scope = new Scope(this);

                scope.enums.Add(new Utils.StoreEntry(name, type, value));
                return(scope);
            }
Exemple #9
0
            public static Int32 GetOffset(ExprType base_type, IReadOnlyList <Int32> indices)
            {
                Int32    offset    = 0;
                ExprType from_type = base_type;

                foreach (Int32 to_index in indices)
                {
                    offset   += GetOffset(from_type, to_index);
                    from_type = GetType(from_type, to_index);
                }
                return(offset);
            }
Exemple #10
0
            public List <ExprType> GetTypes(ExprType base_type, IReadOnlyList <Int32> indices)
            {
                List <ExprType> types = new List <ExprType> {
                    base_type
                };
                ExprType from_type = base_type;

                foreach (Int32 to_index in indices)
                {
                    from_type = GetType(from_type, to_index);
                    types.Add(from_type);
                }
                return(types);
            }
Exemple #11
0
            /// <summary>
            /// Read an expression in the initializer list, locate the corresponding position.
            /// </summary>
            public void Locate(ExprType type)
            {
                switch (type.Kind)
                {
                case ExprTypeKind.STRUCT_OR_UNION:
                    LocateStruct((StructOrUnionType)type);
                    return;

                default:
                    // Even if the expression is of array Type, treat it as a scalar (pointer).
                    LocateScalar();
                    return;
                }
            }
Exemple #12
0
        public override Boolean EqualType(ExprType other)
        {
            return((other is FunctionType) &&
                   (other as FunctionType).HasVarArgs == this.HasVarArgs

                   // same return Type
                   && (other as FunctionType).ReturnType.EqualType(this.ReturnType)

                   // same number of arguments
                   && (other as FunctionType).Args.Count == this.Args.Count

                   // same argument types
                   && (other as FunctionType).Args.Zip(this.Args, (entry1, entry2) => entry1.type.EqualType(entry2.type)).All(_ => _));
        }
Exemple #13
0
        // MakeCast
        // ========
        // input: Expr, Type
        // output: TypeCast
        // converts Expr to Type
        //
        public static Expr MakeCast(Expr expr, ExprType type, Env env)
        {
            // if two types are equal, return Expr
            if (EqualType(expr.Type, type))
            {
                return(expr);
            }

            // from pointer
            if (expr.Type.Kind == ExprTypeKind.POINTER)
            {
                return(FromPointer(expr, type, env));
            }

            // to pointer
            if (type.Kind == ExprTypeKind.POINTER)
            {
                return(ToPointer(expr, type, env));
            }

            switch (expr.Type.Kind)
            {
            // from signed integral
            case ExprTypeKind.CHAR:
            case ExprTypeKind.SHORT:
            case ExprTypeKind.LONG:
                return(SignedIntegralToArith(expr, type));

            // from unsigned integral
            case ExprTypeKind.UCHAR:
            case ExprTypeKind.USHORT:
            case ExprTypeKind.ULONG:
                return(UnsignedIntegralToArith(expr, type));

            // from float
            case ExprTypeKind.FLOAT:
            case ExprTypeKind.DOUBLE:
                return(FloatToArith(expr, type));

            case ExprTypeKind.VOID:
            case ExprTypeKind.POINTER:
            case ExprTypeKind.FUNCTION:
            case ExprTypeKind.ARRAY:
            case ExprTypeKind.INCOMPLETE_ARRAY:
            case ExprTypeKind.STRUCT_OR_UNION:
            default:
                throw new InvalidOperationException("Error: expression Type not supported for casting from.");
            }
        }
Exemple #14
0
            public static Int32 GetOffset(ExprType from_type, Int32 to_index)
            {
                switch (from_type.Kind)
                {
                case ExprTypeKind.ARRAY:
                    return(to_index * ((ArrayType)from_type).ElemType.SizeOf);

                case ExprTypeKind.INCOMPLETE_ARRAY:
                    return(to_index * ((IncompleteArrayType)from_type).ElemType.SizeOf);

                case ExprTypeKind.STRUCT_OR_UNION:
                    return(((StructOrUnionType)from_type).Attribs[to_index].offset);

                default:
                    throw new InvalidProgramException("Not an aggregate Type.");
                }
            }
Exemple #15
0
            public void Next()
            {
                // From base_type to CurType.
                List <ExprType> types = GetTypes(this.base_type, this.indices);

                // We try to jump as many levels out as we can.
                do
                {
                    Int32 index = this.indices.Last();
                    this.indices.RemoveAt(this.indices.Count - 1);

                    types.RemoveAt(types.Count - 1);
                    ExprType type = types.Last();

                    switch (type.Kind)
                    {
                    case ExprTypeKind.ARRAY:
                        if (index < ((ArrayType)type).NumElems - 1)
                        {
                            // There are more elements in the array.
                            this.indices.Add(index + 1);
                            return;
                        }
                        break;

                    case ExprTypeKind.INCOMPLETE_ARRAY:
                        this.indices.Add(index + 1);
                        return;

                    case ExprTypeKind.STRUCT_OR_UNION:
                        if (((StructOrUnionType)type).IsStruct && index < ((StructOrUnionType)type).Attribs.Count - 1)
                        {
                            // There are more members in the struct.
                            // (not union, since we can only initialize the first member of a union)
                            this.indices.Add(index + 1);
                            return;
                        }
                        break;

                    default:
                        break;
                    }
                } while (this.indices.Any());
            }
Exemple #16
0
        public static FunctionType Create(ExprType ret_type, List <Tuple <String, ExprType> > args, Boolean is_varargs)
        {
            Tuple <Int32, IReadOnlyList <Int32> > r_pack = Utils.PackArguments(args.ConvertAll(_ => _.Item2));
            IReadOnlyList <Int32> offsets = r_pack.Item2;

            if (ret_type is StructOrUnionType)
            {
                offsets = offsets.Select(_ => _ + 3 * SIZEOF_POINTER).ToList();
            }
            else
            {
                offsets = offsets.Select(_ => _ + 2 * SIZEOF_POINTER).ToList();
            }
            return(new FunctionType(
                       ret_type,
                       args.Zip(offsets,
                                (name_type, offset) => new Utils.StoreEntry(name_type.Item1, name_type.Item2, offset)
                                ).ToList(),
                       is_varargs
                       ));
        }
Exemple #17
0
        /// <summary>
        /// From:
        ///     pointer
        /// To:
        ///     pointer, integral
        /// </summary>
        public static Expr FromPointer(Expr expr, ExprType type, Env env)
        {
            ExprTypeKind from = expr.Type.Kind;
            ExprTypeKind to   = type.Kind;

            if (from != ExprTypeKind.POINTER)
            {
                throw new InvalidOperationException("Expected a pointer.");
            }

            // if we are casting to another pointer, do a nop
            if (to == ExprTypeKind.POINTER)
            {
                if (expr.IsConstExpr)
                {
                    return(new ConstPtr(((ConstPtr)expr).Value, type, env));
                }
                return(new TypeCast(TypeCastType.NOP, expr, type, env));
            }

            // if we are casting to an integral
            if (type.IsIntegral)
            {
                // pointer -> ulong -> whatever integral
                if (expr.IsConstExpr)
                {
                    expr = new ConstULong(((ConstPtr)expr).Value, env);
                }
                else
                {
                    expr = new TypeCast(TypeCastType.NOP, expr, new ULongType(type.IsConst, type.IsVolatile), env);
                }
                return(MakeCast(expr, type, env));
            }

            throw new InvalidOperationException("Casting from a pointer to an unsupported Type.");
        }
Exemple #18
0
            // PushEntry
            // =========
            // input: loc, name, Type
            // output: Scope
            // returns a new scope with everything the same as this, excpet for a new entry
            //
            public Scope PushEntry(EntryKind loc, String name, ExprType type)
            {
                Scope scope = new Scope(this);

                switch (loc)
                {
                case EntryKind.STACK:
                    scope.esp_pos -= Utils.RoundUp(type.SizeOf, 4);
                    scope.locals.Add(new Utils.StoreEntry(name, type, scope.esp_pos));
                    break;

                case EntryKind.GLOBAL:
                    scope.globals.Add(new Utils.StoreEntry(name, type, 0));
                    break;

                case EntryKind.TYPEDEF:
                    scope.typedefs.Add(new Utils.StoreEntry(name, type, 0));
                    break;

                default:
                    return(null);
                }
                return(scope);
            }
Exemple #19
0
 public Decln(String name, StorageClass scs, ExprType type, Option<Initr> initr) {
     this.name = name;
     this.scs = scs;
     this.type = type;
     this.initr = initr;
 }
Exemple #20
0
 // PushEnum
 // ========
 // input: name, Type
 // output: Environment
 // return a new environment which adds a enum Value
 // 
 public Scope PushEnum(String name, ExprType type, Int32 value) {
     Scope scope = new Scope(this);
     scope.enums.Add(new Utils.StoreEntry(name, type, value));
     return scope;
 }
Exemple #21
0
 // PushEnum
 // ========
 // input: name, Type
 // output: Environment
 // return a new environment which adds a enum Value
 // 
 public Env PushEnum(String name, ExprType type, Int32 value) {
     Scope top = this._scopes.Peek();
     return new Env(this._scopes.Pop().Push(top.PushEnum(name, type, value)));
 }
Exemple #22
0
        /// <summary>
        /// From:
        ///     uchar, ushort, ulong
        /// To:
        ///     char, uchar, short, ushort, long, ulong, float, double
        /// </summary>
        /// <remarks>
        /// Aaccording to MSDN "Conversions from Unsigned Integral Types",
        ///   unsigned long converts directly to double.
        /// However, I just treat unsigned long as long.
        /// </remarks>
        public static Expr UnsignedIntegralToArith(Expr expr, ExprType type) {
            ExprTypeKind from = expr.Type.Kind;
            ExprTypeKind to = type.Kind;

            Env env = expr.Env;

            switch (from) {
                case ExprTypeKind.UCHAR:
                    switch (to) {
                        case ExprTypeKind.CHAR:
                            return new TypeCast(TypeCastType.NOP, expr, type);

                        case ExprTypeKind.SHORT:
                        case ExprTypeKind.USHORT:
                            return new TypeCast(TypeCastType.UINT8_TO_UINT16, expr, type);

                        case ExprTypeKind.LONG:
                        case ExprTypeKind.ULONG:
                            return new TypeCast(TypeCastType.UINT8_TO_UINT32, expr, type);

                        case ExprTypeKind.FLOAT:
                            // uchar -> ulong -> long -> float
                            return new TypeCast(TypeCastType.INT32_TO_FLOAT, new TypeCast(TypeCastType.UINT8_TO_UINT32, expr, new LongType(type.IsConst, type.IsVolatile)), type);

                        case ExprTypeKind.DOUBLE:
                            // uchar -> ulong -> long -> double
                            return new TypeCast(TypeCastType.INT32_TO_DOUBLE, new TypeCast(TypeCastType.UINT8_TO_UINT32, expr, new LongType(type.IsConst, type.IsVolatile)), type);

                        default:
                            Debug.Assert(false);
                            return null;
                    }

                case ExprTypeKind.USHORT:
                    switch (to) {
                        case ExprTypeKind.CHAR:
                        case ExprTypeKind.UCHAR:
                            return new TypeCast(TypeCastType.PRESERVE_INT8, expr, type);

                        case ExprTypeKind.USHORT:
                            return new TypeCast(TypeCastType.NOP, expr, type);

                        case ExprTypeKind.LONG:
                        case ExprTypeKind.ULONG:
                            return new TypeCast(TypeCastType.UINT16_TO_UINT32, expr, type);

                        case ExprTypeKind.FLOAT:
                            // ushort -> ulong -> long -> float
                            return new TypeCast(TypeCastType.INT32_TO_FLOAT, new TypeCast(TypeCastType.UINT16_TO_UINT32, expr, new LongType(type.IsConst, type.IsVolatile)), type);

                        case ExprTypeKind.DOUBLE:
                            // ushort -> ulong -> long -> double
                            return new TypeCast(TypeCastType.INT32_TO_DOUBLE, new TypeCast(TypeCastType.UINT16_TO_UINT32, expr, new LongType(type.IsConst, type.IsVolatile)), type);

                        default:
                            Debug.Assert(false);
                            return null;
                    }

                case ExprTypeKind.ULONG:
                    switch (to) {
                        case ExprTypeKind.CHAR:
                            if (expr.IsConstExpr) {
                                return new ConstLong((SByte)((ConstULong)expr).Value, env);
                            }
                            return new TypeCast(TypeCastType.PRESERVE_INT8, expr, type);

                        case ExprTypeKind.UCHAR:
                            if (expr.IsConstExpr) {
                                return new ConstULong((Byte)((ConstULong)expr).Value, env);
                            }
                            return new TypeCast(TypeCastType.PRESERVE_INT8, expr, type);

                        case ExprTypeKind.SHORT:
                            if (expr.IsConstExpr) {
                                return new ConstLong((Int16)((ConstULong)expr).Value, env);
                            }
                            return new TypeCast(TypeCastType.PRESERVE_INT16, expr, type);

                        case ExprTypeKind.USHORT:
                            if (expr.IsConstExpr) {
                                return new ConstULong((UInt16)((ConstULong)expr).Value, env);
                            }
                            return new TypeCast(TypeCastType.PRESERVE_INT16, expr, type);

                        case ExprTypeKind.LONG:
                            if (expr.IsConstExpr) {
                                return new ConstLong((Int32)((ConstULong)expr).Value, env);
                            }
                            return new TypeCast(TypeCastType.NOP, expr, type);

                        case ExprTypeKind.FLOAT:
                            if (expr.IsConstExpr) {
                                return new ConstFloat(((ConstULong)expr).Value, env);
                            }
                            return new TypeCast(TypeCastType.INT32_TO_FLOAT, expr, type);

                        case ExprTypeKind.DOUBLE:
                            if (expr.IsConstExpr) {
                                return new ConstDouble(((ConstULong)expr).Value, env);
                            }
                            return new TypeCast(TypeCastType.INT32_TO_DOUBLE, expr, type);

                        default:
                            Debug.Assert(false);
                            return null;
                    }

                default:
                    Debug.Assert(false);
                    return null;
            }
        }
Exemple #23
0
 public StoreEntry(String name, ExprType type, Int32 offset)
 {
     this.name   = name;
     this.type   = type;
     this.offset = offset;
 }
Exemple #24
0
            public static Int32 GetOffset(ExprType from_type, Int32 to_index) {
                switch (from_type.Kind) {
                    case ExprTypeKind.ARRAY:
                        return to_index * ((ArrayType)from_type).ElemType.SizeOf;

                    case ExprTypeKind.INCOMPLETE_ARRAY:
                        return to_index * ((IncompleteArrayType)from_type).ElemType.SizeOf;

                    case ExprTypeKind.STRUCT_OR_UNION:
                        return ((StructOrUnionType)from_type).Attribs[to_index].offset;

                    default:
                        throw new InvalidProgramException("Not an aggregate Type.");
                }
            }
Exemple #25
0
 public void Locate(ExprType type) => this.trace.Last().Locate(type);
Exemple #26
0
        /// <summary>
        /// From:
        ///     char, short, long
        /// To:
        ///     char, uchar, short, ushort, long, ulong, float double
        /// </summary>
        public static Expr SignedIntegralToArith(Expr expr, ExprType type)
        {
            ExprTypeKind from = expr.Type.Kind;
            ExprTypeKind to   = type.Kind;

            Env env = expr.Env;

            switch (from)
            {
            case ExprTypeKind.CHAR:
                switch (to)
                {
                case ExprTypeKind.SHORT:
                case ExprTypeKind.USHORT:
                    return(new TypeCast(TypeCastType.INT8_TO_INT16, expr, type));

                case ExprTypeKind.LONG:
                case ExprTypeKind.ULONG:
                    return(new TypeCast(TypeCastType.INT8_TO_INT32, expr, type));

                case ExprTypeKind.UCHAR:
                    return(new TypeCast(TypeCastType.NOP, expr, type));

                case ExprTypeKind.FLOAT:
                    // char -> long -> float
                    return(new TypeCast(TypeCastType.INT32_TO_FLOAT, new TypeCast(TypeCastType.INT8_TO_INT32, expr, new LongType(type.IsConst, type.IsVolatile)), type));

                case ExprTypeKind.DOUBLE:
                    // char -> long -> double
                    return(new TypeCast(TypeCastType.INT32_TO_DOUBLE, new TypeCast(TypeCastType.INT8_TO_INT32, expr, new LongType(type.IsConst, type.IsVolatile)), type));

                case ExprTypeKind.VOID:
                case ExprTypeKind.POINTER:
                case ExprTypeKind.FUNCTION:
                case ExprTypeKind.ARRAY:
                case ExprTypeKind.INCOMPLETE_ARRAY:
                case ExprTypeKind.STRUCT_OR_UNION:
                case ExprTypeKind.CHAR:
                default:
                    throw new InvalidProgramException($"Cannot cast from {from} to {to}");
                }

            case ExprTypeKind.SHORT:
                switch (to)
                {
                case ExprTypeKind.CHAR:
                case ExprTypeKind.UCHAR:
                    return(new TypeCast(TypeCastType.PRESERVE_INT8, expr, type));

                case ExprTypeKind.USHORT:
                    return(new TypeCast(TypeCastType.NOP, expr, type));

                case ExprTypeKind.LONG:
                case ExprTypeKind.ULONG:
                    return(new TypeCast(TypeCastType.INT16_TO_INT32, expr, type));

                case ExprTypeKind.FLOAT:
                    // short -> long -> float
                    return(new TypeCast(TypeCastType.INT32_TO_FLOAT, new TypeCast(TypeCastType.INT16_TO_INT32, expr, new LongType(type.IsConst, type.IsVolatile)), type));

                case ExprTypeKind.DOUBLE:
                    // short -> long -> double
                    return(new TypeCast(TypeCastType.INT32_TO_DOUBLE, new TypeCast(TypeCastType.INT16_TO_INT32, expr, new LongType(type.IsConst, type.IsVolatile)), type));

                case ExprTypeKind.VOID:
                case ExprTypeKind.SHORT:
                case ExprTypeKind.POINTER:
                case ExprTypeKind.FUNCTION:
                case ExprTypeKind.ARRAY:
                case ExprTypeKind.INCOMPLETE_ARRAY:
                case ExprTypeKind.STRUCT_OR_UNION:
                default:
                    throw new InvalidProgramException($"Cannot cast from {from} to {to}");
                }

            case ExprTypeKind.LONG:
                switch (to)
                {
                case ExprTypeKind.CHAR:
                    if (expr.IsConstExpr)
                    {
                        return(new ConstChar((SByte)((ConstLong)expr).Value, env));
                    }
                    return(new TypeCast(TypeCastType.PRESERVE_INT8, expr, type));

                case ExprTypeKind.UCHAR:
                    if (expr.IsConstExpr)
                    {
                        return(new ConstUChar((Byte)((ConstLong)expr).Value, env));
                    }
                    return(new TypeCast(TypeCastType.PRESERVE_INT8, expr, type));

                case ExprTypeKind.SHORT:
                    if (expr.IsConstExpr)
                    {
                        return(new ConstShort((Int16)((ConstLong)expr).Value, env));
                    }
                    return(new TypeCast(TypeCastType.PRESERVE_INT16, expr, type));

                case ExprTypeKind.USHORT:
                    if (expr.IsConstExpr)
                    {
                        return(new ConstUShort((UInt16)((ConstLong)expr).Value, env));
                    }
                    return(new TypeCast(TypeCastType.PRESERVE_INT16, expr, type));

                case ExprTypeKind.ULONG:
                    if (expr.IsConstExpr)
                    {
                        return(new ConstULong((UInt32)((ConstLong)expr).Value, env));
                    }
                    return(new TypeCast(TypeCastType.NOP, expr, type));

                case ExprTypeKind.FLOAT:
                    if (expr.IsConstExpr)
                    {
                        return(new ConstFloat(((ConstLong)expr).Value, env));
                    }
                    return(new TypeCast(TypeCastType.INT32_TO_FLOAT, expr, type));

                case ExprTypeKind.DOUBLE:
                    if (expr.IsConstExpr)
                    {
                        return(new ConstDouble(((ConstLong)expr).Value, env));
                    }
                    return(new TypeCast(TypeCastType.INT32_TO_DOUBLE, expr, type));

                case ExprTypeKind.VOID:
                case ExprTypeKind.LONG:
                case ExprTypeKind.POINTER:
                case ExprTypeKind.FUNCTION:
                case ExprTypeKind.ARRAY:
                case ExprTypeKind.INCOMPLETE_ARRAY:
                case ExprTypeKind.STRUCT_OR_UNION:
                default:
                    throw new InvalidProgramException($"Cannot cast from {from} to {to}");
                }

            default:
                throw new InvalidProgramException();
            }
        }
Exemple #27
0
 public Attribute(Expr expr, String name, ExprType type) {
     this.Expr = expr;
     this.Name = name;
     this.Type = type;
 }
Exemple #28
0
 public static Expr MakeCast(Expr expr, ExprType type) =>
 MakeCast(expr, type, expr.Env);
Exemple #29
0
 public static Boolean EqualType(ExprType t1, ExprType t2) {
     return t1.EqualType(t2);
 }
Exemple #30
0
 public static Boolean EqualType(ExprType t1, ExprType t2)
 {
     return(t1.EqualType(t2));
 }
Exemple #31
0
 public static Expr MakeCast(Expr expr, ExprType type) =>
     MakeCast(expr, type, expr.Env);
Exemple #32
0
        /// <summary>
        /// From:
        ///     pointer, integral
        /// To:
        ///     pointer
        /// </summary>
        public static Expr ToPointer(Expr expr, ExprType type, Env env)
        {
            ExprTypeKind from = expr.Type.Kind;
            ExprTypeKind to   = type.Kind;

            if (to != ExprTypeKind.POINTER)
            {
                throw new InvalidOperationException("Error: expected casting to pointer.");
            }

            if (from == ExprTypeKind.POINTER)
            {
                if (expr.IsConstExpr)
                {
                    return(new ConstPtr(((ConstPtr)expr).Value, type, env));
                }
                return(new TypeCast(TypeCastType.NOP, expr, type, env));
            }

            if (expr.Type.IsIntegral)
            {
                // if we are casting from an integral

                // whatever integral -> ulong
                switch (expr.Type.Kind)
                {
                case ExprTypeKind.CHAR:
                case ExprTypeKind.SHORT:
                case ExprTypeKind.LONG:
                    expr = SignedIntegralToArith(expr, new ULongType(type.IsConst, type.IsVolatile));
                    break;

                case ExprTypeKind.UCHAR:
                case ExprTypeKind.USHORT:
                case ExprTypeKind.ULONG:
                    expr = UnsignedIntegralToArith(expr, new ULongType(type.IsConst, type.IsVolatile));
                    break;

                default:
                    break;
                }

                // ulong -> pointer
                if (expr.IsConstExpr)
                {
                    return(new ConstPtr(((ConstULong)expr).Value, type, env));
                }
                return(new TypeCast(TypeCastType.NOP, expr, type, env));
            }
            if (expr.Type is FunctionType)
            {
                if (!expr.Type.EqualType(((PointerType)type).RefType))
                {
                    throw new InvalidOperationException("Casting from an incompatible function.");
                }

                // TODO: only allow compatible Type?
                return(new TypeCast(TypeCastType.NOP, expr, type, env));
            }
            if (expr.Type is ArrayType)
            {
                // TODO: allow any pointer Type to cast to?
                return(new TypeCast(TypeCastType.NOP, expr, type, env));
            }

            throw new InvalidOperationException("Error: casting from an unsupported Type to pointer.");
        }
Exemple #33
0
 public void Iterate(ExprType type, Action<Int32, Expr> action) => Iterate(new MemberIterator(type), action);
Exemple #34
0
 public Dereference(Expr expr, ExprType type) {
     this.Expr = expr;
     this.Type = type;
 }
Exemple #35
0
 public Status(ExprType base_type) {
     this.base_type = base_type;
     this.indices = new List<Int32>();
 }
Exemple #36
0
 public Variable(ExprType type, String name, Env env) {
     this.Name = name;
     this.Env = env;
     this.Type = type;
 }
Exemple #37
0
 public List<ExprType> GetTypes(ExprType base_type, IReadOnlyList<Int32> indices) {
     List<ExprType> types = new List<ExprType> { base_type };
     ExprType from_type = base_type;
     foreach (Int32 to_index in indices) {
         from_type = GetType(from_type, to_index);
         types.Add(from_type);
     }
     return types;
 }
Exemple #38
0
 public ConditionalExpr(Expr cond, Expr trueExpr, Expr falseExpr, ExprType type) {
     this.Cond = cond;
     this.TrueExpr = trueExpr;
     this.FalseExpr = falseExpr;
     this.Type = type;
 }
Exemple #39
0
        /// <summary>
        /// From:
        ///     char, short, long
        /// To:
        ///     char, uchar, short, ushort, long, ulong, float double
        /// </summary>
        public static Expr SignedIntegralToArith(Expr expr, ExprType type) {
            ExprTypeKind from = expr.Type.Kind;
            ExprTypeKind to = type.Kind;

            Env env = expr.Env;

            switch (from) {
                case ExprTypeKind.CHAR:
                    switch (to) {
                        case ExprTypeKind.SHORT:
                        case ExprTypeKind.USHORT:
                            return new TypeCast(TypeCastType.INT8_TO_INT16, expr, type);

                        case ExprTypeKind.LONG:
                        case ExprTypeKind.ULONG:
                            return new TypeCast(TypeCastType.INT8_TO_INT32, expr, type);

                        case ExprTypeKind.UCHAR:
                            return new TypeCast(TypeCastType.NOP, expr, type);

                        case ExprTypeKind.FLOAT:
                            // char -> long -> float
                            return new TypeCast(TypeCastType.INT32_TO_FLOAT, new TypeCast(TypeCastType.INT8_TO_INT32, expr, new LongType(type.IsConst, type.IsVolatile)), type);

                        case ExprTypeKind.DOUBLE:
                            // char -> long -> double
                            return new TypeCast(TypeCastType.INT32_TO_DOUBLE, new TypeCast(TypeCastType.INT8_TO_INT32, expr, new LongType(type.IsConst, type.IsVolatile)), type);

                        case ExprTypeKind.VOID:
                        case ExprTypeKind.POINTER:
                        case ExprTypeKind.FUNCTION:
                        case ExprTypeKind.ARRAY:
                        case ExprTypeKind.INCOMPLETE_ARRAY:
                        case ExprTypeKind.STRUCT_OR_UNION:
                        case ExprTypeKind.CHAR:
                        default:
                            throw new InvalidProgramException($"Cannot cast from {from} to {to}");
                    }

                case ExprTypeKind.SHORT:
                    switch (to) {
                        case ExprTypeKind.CHAR:
                        case ExprTypeKind.UCHAR:
                            return new TypeCast(TypeCastType.PRESERVE_INT8, expr, type);

                        case ExprTypeKind.USHORT:
                            return new TypeCast(TypeCastType.NOP, expr, type);

                        case ExprTypeKind.LONG:
                        case ExprTypeKind.ULONG:
                            return new TypeCast(TypeCastType.INT16_TO_INT32, expr, type);

                        case ExprTypeKind.FLOAT:
                            // short -> long -> float
                            return new TypeCast(TypeCastType.INT32_TO_FLOAT, new TypeCast(TypeCastType.INT16_TO_INT32, expr, new LongType(type.IsConst, type.IsVolatile)), type);

                        case ExprTypeKind.DOUBLE:
                            // short -> long -> double
                            return new TypeCast(TypeCastType.INT32_TO_DOUBLE, new TypeCast(TypeCastType.INT16_TO_INT32, expr, new LongType(type.IsConst, type.IsVolatile)), type);

                        case ExprTypeKind.VOID:
                        case ExprTypeKind.SHORT:
                        case ExprTypeKind.POINTER:
                        case ExprTypeKind.FUNCTION:
                        case ExprTypeKind.ARRAY:
                        case ExprTypeKind.INCOMPLETE_ARRAY:
                        case ExprTypeKind.STRUCT_OR_UNION:
                        default:
                            throw new InvalidProgramException($"Cannot cast from {from} to {to}");
                    }

                case ExprTypeKind.LONG:
                    switch (to) {
                        case ExprTypeKind.CHAR:
                            if (expr.IsConstExpr) {
                                return new ConstChar((SByte)((ConstLong)expr).Value, env);
                            }
                            return new TypeCast(TypeCastType.PRESERVE_INT8, expr, type);

                        case ExprTypeKind.UCHAR:
                            if (expr.IsConstExpr) {
                                return new ConstUChar((Byte)((ConstLong)expr).Value, env);
                            }
                            return new TypeCast(TypeCastType.PRESERVE_INT8, expr, type);

                        case ExprTypeKind.SHORT:
                            if (expr.IsConstExpr) {
                                return new ConstShort((Int16)((ConstLong)expr).Value, env);
                            }
                            return new TypeCast(TypeCastType.PRESERVE_INT16, expr, type);

                        case ExprTypeKind.USHORT:
                            if (expr.IsConstExpr) {
                                return new ConstUShort((UInt16)((ConstLong)expr).Value, env);
                            }
                            return new TypeCast(TypeCastType.PRESERVE_INT16, expr, type);

                        case ExprTypeKind.ULONG:
                            if (expr.IsConstExpr) {
                                return new ConstULong((UInt32)((ConstLong)expr).Value, env);
                            }
                            return new TypeCast(TypeCastType.NOP, expr, type);

                        case ExprTypeKind.FLOAT:
                            if (expr.IsConstExpr) {
                                return new ConstFloat(((ConstLong)expr).Value, env);
                            }
                            return new TypeCast(TypeCastType.INT32_TO_FLOAT, expr, type);

                        case ExprTypeKind.DOUBLE:
                            if (expr.IsConstExpr) {
                                return new ConstDouble(((ConstLong)expr).Value, env);
                            }
                            return new TypeCast(TypeCastType.INT32_TO_DOUBLE, expr, type);

                        case ExprTypeKind.VOID:
                        case ExprTypeKind.LONG:
                        case ExprTypeKind.POINTER:
                        case ExprTypeKind.FUNCTION:
                        case ExprTypeKind.ARRAY:
                        case ExprTypeKind.INCOMPLETE_ARRAY:
                        case ExprTypeKind.STRUCT_OR_UNION:
                        default:
                            throw new InvalidProgramException($"Cannot cast from {from} to {to}");
                    }

                default:
                    throw new InvalidProgramException();
            }
        }
Exemple #40
0
        // MakeCast
        // ========
        // input: Expr, Type
        // output: TypeCast
        // converts Expr to Type
        // 
        public static Expr MakeCast(Expr expr, ExprType type, Env env) {

            // if two types are equal, return Expr
            if (EqualType(expr.Type, type)) {
                return expr;
            }

            // from pointer
            if (expr.Type.Kind == ExprTypeKind.POINTER) {
                return FromPointer(expr, type, env);
            }

            // to pointer
            if (type.Kind == ExprTypeKind.POINTER) {
                return ToPointer(expr, type, env);
            }

            switch (expr.Type.Kind) {
                // from signed integral
                case ExprTypeKind.CHAR:
                case ExprTypeKind.SHORT:
                case ExprTypeKind.LONG:
                    return SignedIntegralToArith(expr, type);

                // from unsigned integral
                case ExprTypeKind.UCHAR:
                case ExprTypeKind.USHORT:
                case ExprTypeKind.ULONG:
                    return UnsignedIntegralToArith(expr, type);

                // from float
                case ExprTypeKind.FLOAT:
                case ExprTypeKind.DOUBLE:
                    return FloatToArith(expr, type);

                case ExprTypeKind.VOID:
                case ExprTypeKind.POINTER:
                case ExprTypeKind.FUNCTION:
                case ExprTypeKind.ARRAY:
                case ExprTypeKind.INCOMPLETE_ARRAY:
                case ExprTypeKind.STRUCT_OR_UNION:
                default:
                    throw new InvalidOperationException("Error: expression Type not supported for casting from.");
            }

        }
Exemple #41
0
 public void Locate(ExprType type) => this.trace.Last().Locate(type);
Exemple #42
0
 public Initr ConformType(ExprType type) => ConformType(new MemberIterator(type));
Exemple #43
0
 // PushEntry
 // =========
 // input: loc, name, Type
 // output: Scope
 // returns a new scope with everything the same as this, excpet for a new entry
 // 
 public Scope PushEntry(EntryKind loc, String name, ExprType type) {
     Scope scope = new Scope(this);
     switch (loc) {
     case EntryKind.STACK:
         scope.esp_pos -= Utils.RoundUp(type.SizeOf, 4);
         scope.locals.Add(new Utils.StoreEntry(name, type, scope.esp_pos));
         break;
     case EntryKind.GLOBAL:
         scope.globals.Add(new Utils.StoreEntry(name, type, 0));
         break;
     case EntryKind.TYPEDEF:
         scope.typedefs.Add(new Utils.StoreEntry(name, type, 0));
         break;
     default:
         return null;
     }
     return scope;
 }
Exemple #44
0
        /// <summary>
        /// From:
        ///     pointer, integral
        /// To:
        ///     pointer
        /// </summary>
        public static Expr ToPointer(Expr expr, ExprType type, Env env) {
            ExprTypeKind from = expr.Type.Kind;
            ExprTypeKind to = type.Kind;

            if (to != ExprTypeKind.POINTER) {
                throw new InvalidOperationException("Error: expected casting to pointer.");
            }

            if (from == ExprTypeKind.POINTER) {
                if (expr.IsConstExpr) {
                    return new ConstPtr(((ConstPtr)expr).Value, type, env);
                }
                return new TypeCast(TypeCastType.NOP, expr, type, env);
            }

            if (expr.Type.IsIntegral) {
                // if we are casting from an integral

                // whatever integral -> ulong
                switch (expr.Type.Kind) {
                    case ExprTypeKind.CHAR:
                    case ExprTypeKind.SHORT:
                    case ExprTypeKind.LONG:
                        expr = SignedIntegralToArith(expr, new ULongType(type.IsConst, type.IsVolatile));
                        break;
                    case ExprTypeKind.UCHAR:
                    case ExprTypeKind.USHORT:
                    case ExprTypeKind.ULONG:
                        expr = UnsignedIntegralToArith(expr, new ULongType(type.IsConst, type.IsVolatile));
                        break;
                    default:
                        break;
                }

                // ulong -> pointer
                if (expr.IsConstExpr) {
                    return new ConstPtr(((ConstULong)expr).Value, type, env);
                }
                return new TypeCast(TypeCastType.NOP, expr, type, env);
            }
            if (expr.Type is FunctionType) {
                if (!expr.Type.EqualType(((PointerType)type).RefType)) {
                    throw new InvalidOperationException("Casting from an incompatible function.");
                }

                // TODO: only allow compatible Type?
                return new TypeCast(TypeCastType.NOP, expr, type, env);

            }
            if (expr.Type is ArrayType) {

                // TODO: allow any pointer Type to cast to?
                return new TypeCast(TypeCastType.NOP, expr, type, env);
            }

            throw new InvalidOperationException("Error: casting from an unsupported Type to pointer.");
        }
Exemple #45
0
 // PushEntry
 // =========
 // input: loc, name, Type
 // ouput: Environment
 // return a new environment which adds a symbol entry
 // 
 public Env PushEntry(EntryKind loc, String name, ExprType type) {
     Scope top = this._scopes.Peek();
     return new Env(this._scopes.Pop().Push(top.PushEntry(loc, name, type)));
 }
Exemple #46
0
 public MemberIterator(ExprType type)
 {
     this.trace = new List <Status> {
         new Status(type)
     };
 }
Exemple #47
0
 public Entry(EntryKind kind, ExprType type, Int32 offset) {
     this.Kind = kind;
     this.Type = type;
     this.Offset = offset;
 }
Exemple #48
0
 public Status(ExprType base_type)
 {
     this.base_type = base_type;
     this.indices   = new List <Int32>();
 }
Exemple #49
0
 public Initr ConformType(ExprType type) => ConformType(new MemberIterator(type));
Exemple #50
0
 public static ExprType GetType(ExprType base_type, IReadOnlyList <Int32> indices) =>
 indices.Aggregate(base_type, GetType);
Exemple #51
0
 public MemberIterator(ExprType type) {
     this.trace = new List<Status> { new Status(type) };
 }
Exemple #52
0
        /// <summary>
        /// From:
        ///     pointer
        /// To:
        ///     pointer, integral
        /// </summary>
        public static Expr FromPointer(Expr expr, ExprType type, Env env) {
            ExprTypeKind from = expr.Type.Kind;
            ExprTypeKind to = type.Kind;

            if (from != ExprTypeKind.POINTER) {
                throw new InvalidOperationException("Expected a pointer.");
            }

            // if we are casting to another pointer, do a nop
            if (to == ExprTypeKind.POINTER) {
                if (expr.IsConstExpr) {
                    return new ConstPtr(((ConstPtr)expr).Value, type, env);
                }
                return new TypeCast(TypeCastType.NOP, expr, type, env);
            }

            // if we are casting to an integral
            if (type.IsIntegral) {
                // pointer -> ulong -> whatever integral
                if (expr.IsConstExpr) {
                    expr = new ConstULong(((ConstPtr)expr).Value, env);
                } else {
                    expr = new TypeCast(TypeCastType.NOP, expr, new ULongType(type.IsConst, type.IsVolatile), env);
                }
                return MakeCast(expr, type, env);
            }

            throw new InvalidOperationException("Casting from a pointer to an unsupported Type.");
        }
Exemple #53
0
 public static ExprType GetType(ExprType base_type, IReadOnlyList<Int32> indices) =>
     indices.Aggregate(base_type, GetType);
Exemple #54
0
 public TypeCast(TypeCastType kind, Expr expr, ExprType type)
     : this(kind, expr, type, expr.Env) { }
Exemple #55
0
 public static Int32 GetOffset(ExprType base_type, IReadOnlyList<Int32> indices) {
     Int32 offset = 0;
     ExprType from_type = base_type;
     foreach (Int32 to_index in indices) {
         offset += GetOffset(from_type, to_index);
         from_type = GetType(from_type, to_index);
     }
     return offset;
 }
Exemple #56
0
        /// <summary>
        /// From:
        ///     float, double
        /// To:
        ///     char, uchar, short, ushort, long, ulong, float, double
        /// </summary>
        /// <remarks>
        /// According to MSDN "Conversions from Floating-Point Types",
        ///   float cannot convert to unsigned char.
        /// I don't know why, but I follow it.
        /// </remarks>
        public static Expr FloatToArith(Expr expr, ExprType type) {

            ExprTypeKind from = expr.Type.Kind;
            ExprTypeKind to = type.Kind;
            Env env = expr.Env;

            switch (from) {
                case ExprTypeKind.FLOAT:
                    switch (to) {
                        case ExprTypeKind.CHAR:
                            if (expr.IsConstExpr) {
                                return new ConstLong((SByte)((ConstFloat)expr).Value, env);
                            }
                            return new TypeCast(TypeCastType.PRESERVE_INT8, new TypeCast(TypeCastType.FLOAT_TO_INT32, expr, new LongType(type.IsConst, type.IsVolatile)), type);

                        case ExprTypeKind.SHORT:
                            if (expr.IsConstExpr) {
                                return new ConstLong((Int16)((ConstFloat)expr).Value, env);
                            }
                            return new TypeCast(TypeCastType.PRESERVE_INT16, new TypeCast(TypeCastType.FLOAT_TO_INT32, expr, new LongType(type.IsConst, type.IsVolatile)), type);

                        case ExprTypeKind.USHORT:
                            if (expr.IsConstExpr) {
                                return new ConstULong((UInt16)((ConstFloat)expr).Value, env);
                            }
                            return new TypeCast(TypeCastType.PRESERVE_INT16, new TypeCast(TypeCastType.FLOAT_TO_INT32, expr, new LongType(type.IsConst, type.IsVolatile)), type);

                        case ExprTypeKind.LONG:
                            if (expr.IsConstExpr) {
                                return new ConstLong((Int32)((ConstFloat)expr).Value, env);
                            }
                            return new TypeCast(TypeCastType.FLOAT_TO_INT32, expr, type);

                        case ExprTypeKind.ULONG:
                            if (expr.IsConstExpr) {
                                return new ConstULong((UInt32)((ConstFloat)expr).Value, env);
                            }
                            return new TypeCast(TypeCastType.FLOAT_TO_INT32, expr, type);

                        case ExprTypeKind.DOUBLE:
                            if (expr.IsConstExpr) {
                                return new ConstDouble(((ConstFloat)expr).Value, env);
                            }
                            return new TypeCast(TypeCastType.FLOAT_TO_DOUBLE, expr, type);

                        default:
                            throw new InvalidProgramException();
                    }

                case ExprTypeKind.DOUBLE:
                    switch (to) {
                        case ExprTypeKind.CHAR:
                            // double -> float -> char
                            if (expr.IsConstExpr) {
                                return new ConstLong((SByte)((ConstDouble)expr).Value, env);
                            }
                            return FloatToArith(FloatToArith(expr, new FloatType(type.IsConst, type.IsVolatile)), new CharType(type.IsConst, type.IsVolatile));

                        case ExprTypeKind.SHORT:
                            // double -> float -> short
                            if (expr.IsConstExpr) {
                                return new ConstLong((Int16)((ConstDouble)expr).Value, env);
                            }
                            return FloatToArith(FloatToArith(expr, new FloatType(type.IsConst, type.IsVolatile)), new ShortType(type.IsConst, type.IsVolatile));

                        case ExprTypeKind.LONG:
                            // double -> float -> short
                            if (expr.IsConstExpr) {
                                return new ConstLong((Int32)((ConstDouble)expr).Value, env);
                            }
                            return new TypeCast(TypeCastType.DOUBLE_TO_INT32, expr, type);

                        case ExprTypeKind.ULONG:
                            if (expr.IsConstExpr) {
                                return new ConstULong((UInt32)((ConstDouble)expr).Value, env);
                            }
                            return new TypeCast(TypeCastType.DOUBLE_TO_INT32, expr, type);

                        case ExprTypeKind.USHORT:
                            // double -> long -> ushort
                            if (expr.IsConstExpr) {
                                return new ConstULong((UInt16)((ConstDouble)expr).Value, env);
                            }
                            return new TypeCast(TypeCastType.PRESERVE_INT16, new TypeCast(TypeCastType.DOUBLE_TO_INT32, expr, new LongType(type.IsConst, type.IsVolatile)), type);

                        case ExprTypeKind.FLOAT:
                            if (expr.IsConstExpr) {
                                return new ConstFloat((Single)((ConstDouble)expr).Value, env);
                            }
                            return new TypeCast(TypeCastType.DOUBLE_TO_FLOAT, expr, type);

                        default:
                            throw new InvalidProgramException();
                    }

                default:
                    throw new InvalidProgramException();
            }
        }
Exemple #57
0
 /// <summary>
 /// Read an expression in the initializer list, locate the corresponding position.
 /// </summary>
 public void Locate(ExprType type) {
     switch (type.Kind) {
         case ExprTypeKind.STRUCT_OR_UNION:
             LocateStruct((StructOrUnionType)type);
             return;
         default:
             // Even if the expression is of array Type, treat it as a scalar (pointer).
             LocateScalar();
             return;
     }
 }
Exemple #58
0
 private TypeCast(TypeCastType kind, Expr expr, ExprType type, Env env) {
     this.Expr = expr;
     this.Kind = kind;
     this.Type = type;
     this.Env = env;
 }
Exemple #59
0
 public void Iterate(ExprType type, Action <Int32, Expr> action) => Iterate(new MemberIterator(type), action);
Exemple #60
0
 public TypeCast(TypeCastType kind, Expr expr, ExprType type)
     : this(kind, expr, type, expr.Env)
 {
 }