Example #1
0
        private void EmitSetupType(Seq<JST.Statement> body, JST.Expression lhs)
        {
            // NOTE: We always emit the SetupType function, even if the body is empty, so that we can
            //       track which types are at phase 3. (We need to initialize base types and type arguments
            //       to phase 3 when type itself is brought up to phase 3.)

            // Collect static fields and their types
            // NOTE: We used to also bind null instance fields into the prototype, but this turns out to
            //       be a significant performance hit
            var staticFields = new Seq<CST.FieldRef>();
            var usage = new CST.Usage();
            foreach (var fieldDef in Parent.Fields.Where(f => f.IsStatic))
            {
                var fieldRef = new CST.FieldRef(TypeCompEnv.TypeRef, fieldDef.FieldSignature);
                if (TypeCompEnv.Type.Style is CST.EnumTypeStyle || fieldDef.Init == null ||
                    fieldDef.Init.Flavor != CST.FieldInitFlavor.Const)
                {
                    staticFields.Add(fieldRef);
                    if (Env.JSTHelpers.DefaultFieldValueIsNonNull(TypeCompEnv, fieldRef))
                        // We'll need type to construct default
                        fieldRef.ExternalFieldType.AccumUsage(usage, true);
                }
                // else: constant static fields, other than enums, don't need any run-time representation
            }

            var innerBody = new Seq<JST.Statement>();
            var innerTypeCompEnv = TypeCompEnv.EnterFunction();

            innerTypeCompEnv.BindUsage(innerBody, usage, TypePhase.Constructed);

            if (staticFields.Count > 0)
            {
                if (Env.DebugMode)
                    innerBody.Add(new JST.CommentStatement("Static fields"));
                foreach (var fieldRef in staticFields)
                {
                    innerBody.Add
                        (JST.Statement.DotAssignment
                             (TypeId.ToE(),
                              Env.JSTHelpers.ResolveFieldToIdentifier(innerTypeCompEnv, fieldRef, true),
                              Env.JSTHelpers.DefaultFieldValue(innerTypeCompEnv, fieldRef)));
                }
            }

            if (Parent.StaticInitializer != null)
            {
                if (Env.DebugMode)
                    innerBody.Add(new JST.CommentStatement("Static constructor"));
                innerBody.Add
                    (new JST.ExpressionStatement
                         (innerTypeCompEnv.MethodCallExpression
                              (Parent.StaticInitializer, innerTypeCompEnv.NameSupply, false, JST.Constants.EmptyExpressions)));
            }

            EmitReflection(innerBody, innerTypeCompEnv, TypeId.ToE());

            body.Add
                (JST.Statement.DotAssignment
                     (lhs, Constants.TypeSetupType, new JST.FunctionExpression(null, new JST.Statements(innerBody))));
        }
Example #2
0
        private void EmitEquals(Seq<JST.Statement> body, JST.Expression lhs)
        {
            var innerNameSupply = NameSupply.Fork();
            var parameters = new Seq<JST.Identifier>();
            parameters.Add(innerNameSupply.GenSym());
            var left = parameters[0].ToE();
            parameters.Add(innerNameSupply.GenSym());
            var right = parameters[1].ToE();
            var innerBody = new Seq<JST.Statement>();

            var iequatableTypeRef = Env.Global.IEquatableTypeConstructorRef.ApplyTo(TypeCompEnv.TypeRef);
            var hasIEquatable = TypeCompEnv.TypeRef.IsAssignableTo(TypeCompEnv, iequatableTypeRef);

            var s = TypeCompEnv.Type.Style;

            if (s is CST.VoidTypeStyle || s is CST.ManagedPointerTypeStyle)
                innerBody.Add
                    (new JST.ThrowStatement
                         (JST.Expression.DotCall(RootId.ToE(), Constants.RootInvalidOperationException)));
            else if (s is CST.NumberTypeStyle || s is CST.EnumTypeStyle || TypeCompEnv.TypeRef.Equals(Env.Global.DecimalRef))
                innerBody.Add(new JST.ReturnStatement(new JST.BinaryExpression(left, JST.BinaryOp.Equals, right)));
            else if (s is CST.HandleTypeStyle)
            {
                innerBody.Add
                    (new JST.IfStatement
                         (JST.Expression.IsNull(left), new JST.Statements(new JST.ReturnStatement(JST.Expression.IsNull(right)))));
                innerBody.Add
                    (new JST.IfStatement
                         (JST.Expression.IsNull(right), new JST.Statements(new JST.ReturnStatement(new JST.BooleanLiteral(false)))));
                innerBody.Add
                    (new JST.ReturnStatement(new JST.BinaryExpression(left, JST.BinaryOp.StrictEquals, right)));
            }
            else if (s is CST.NullableTypeStyle)
            {
                innerBody.Add
                    (new JST.IfStatement
                         (JST.Expression.IsNull(left), new JST.Statements(new JST.ReturnStatement(JST.Expression.IsNull(right)))));
                innerBody.Add
                    (new JST.IfStatement
                         (JST.Expression.IsNull(right), new JST.Statements(new JST.ReturnStatement(new JST.BooleanLiteral(false)))));
                innerBody.Add
                    (new JST.ReturnStatement
                         (JST.Expression.DotCall
                              (TypeCompEnv.ResolveType(TypeCompEnv.TypeBoundArguments[0], TypePhase.Slots),
                               Constants.TypeEquals,
                               left,
                               right)));
            }
            else if (s is CST.StructTypeStyle)
            {
                if (hasIEquatable)
                {
                    // Defer to IEquatable<T>::Equals
                    var paramTypeRef = new CST.ParameterTypeRef(CST.ParameterFlavor.Type, 0);
                    var equalsRef = new CST.MethodRef
                        (iequatableTypeRef,
                         "Equals",
                         false,
                         null,
                         new Seq<CST.TypeRef> { paramTypeRef, paramTypeRef },
                         Env.Global.BooleanRef);
                    var leftPtr = JST.Expression.DotCall
                        (RootId.ToE(), Constants.RootNewPointerToValue, left, lhs);
                    var call = Env.JSTHelpers.DefaultVirtualMethodCallExpression
                        (TypeCompEnv,
                         innerNameSupply,
                         innerBody,
                         equalsRef,
                         new Seq<JST.Expression> { leftPtr, right });
                    innerBody.Add(new JST.ReturnStatement(call));
                }
                else
                {
                    foreach (var fieldDef in Parent.Fields.Where(f => !f.IsStatic))
                    {
                        var fieldRef = new CST.FieldRef(TypeCompEnv.TypeRef, fieldDef.FieldSignature);
                        var leftField = Env.JSTHelpers.ResolveInstanceField(TypeCompEnv, left, fieldRef);
                        var rightField = Env.JSTHelpers.ResolveInstanceField(TypeCompEnv, right, fieldRef);
                        innerBody.Add
                            (new JST.IfStatement
                                 (JST.Expression.Not
                                      (JST.Expression.DotCall
                                           (TypeCompEnv.ResolveType(fieldDef.FieldType, TypePhase.Slots),
                                            Constants.TypeEquals,
                                            leftField,
                                            rightField)),
                                  new JST.Statements(new JST.ReturnStatement(new JST.BooleanLiteral(false)))));
                    }
                    innerBody.Add(new JST.ReturnStatement(new JST.BooleanLiteral(true)));
                }
            }
            else if (s is CST.ObjectTypeStyle || (s is CST.ClassTypeStyle & hasIEquatable))
            {
                innerBody.Add
                    (new JST.IfStatement
                         (JST.Expression.IsNull(left), new JST.Statements(new JST.ReturnStatement(JST.Expression.IsNull(right)))));
                innerBody.Add
                    (new JST.IfStatement
                         (JST.Expression.IsNull(right), new JST.Statements(new JST.ReturnStatement(new JST.BooleanLiteral(false)))));
                var equalsRef = default(CST.MethodRef);
                if (hasIEquatable)
                {
                    // Defer to IEquatable<T>::Equals
                    var paramTypeRef = new CST.ParameterTypeRef(CST.ParameterFlavor.Type, 0);
                    var iequatableSelfTypeRef = Env.Global.IEquatableTypeConstructorRef.ApplyTo(paramTypeRef);
                    equalsRef = new CST.MethodRef
                        (iequatableTypeRef,
                         "Equals",
                         false,
                         null,
                         new Seq<CST.TypeRef> { iequatableSelfTypeRef, paramTypeRef },
                         Env.Global.BooleanRef);
                }
                else
                {
                    // Defer to Object::Equals virtual
                    equalsRef = new CST.MethodRef
                        (Env.Global.ObjectRef,
                         "Equals",
                         false,
                         null,
                         new Seq<CST.TypeRef> { Env.Global.ObjectRef, Env.Global.ObjectRef },
                         Env.Global.BooleanRef);
                }
                var call = Env.JSTHelpers.DefaultVirtualMethodCallExpression
                    (TypeCompEnv, innerNameSupply, innerBody, equalsRef, new Seq<JST.Expression> { left, right });
                innerBody.Add(new JST.ReturnStatement(call));
            }
            else
                // default is ok
                return;

            body.Add
                (JST.Statement.DotAssignment
                     (lhs, Constants.TypeEquals, new JST.FunctionExpression(parameters, new JST.Statements(innerBody))));
        }
Example #3
0
        private void EmitHash(Seq<JST.Statement> body, JST.Expression lhs)
        {
            var innerNameSupply = NameSupply.Fork();
            var parameters = new Seq<JST.Identifier>();
            parameters.Add(innerNameSupply.GenSym());
            var obj = parameters[0].ToE();
            var innerBody = new Seq<JST.Statement>();

            var s = TypeCompEnv.Type.Style;

            if (s is CST.VoidTypeStyle || s is CST.ManagedPointerTypeStyle)
                innerBody.Add
                    (new JST.ThrowStatement
                         (JST.Expression.DotCall(RootId.ToE(), Constants.RootInvalidOperationException)));
            else if (s is CST.NumberTypeStyle || s is CST.EnumTypeStyle || TypeCompEnv.TypeRef.Equals(Env.Global.DecimalRef))
                innerBody.Add(new JST.ReturnStatement(obj));
            else if (s is CST.HandleTypeStyle)
            {
                innerBody.Add
                    (new JST.IfStatement
                         (JST.Expression.IsNull(obj), new JST.Statements(new JST.ReturnStatement(new JST.NumericLiteral(0)))));
                var objid = JST.Expression.Dot(obj, Constants.ObjectId);
                innerBody.Add
                    (new JST.IfStatement
                         (JST.Expression.IsNull(objid),
                          new JST.Statements(JST.Statement.Assignment
                              (objid,
                               new JST.UnaryExpression
                                   (JST.Expression.Dot(RootId.ToE(), Constants.RootNextObjectId),
                                    JST.UnaryOp.PostIncrement)))));
                innerBody.Add(new JST.ReturnStatement(objid));
            }
            else if (s is CST.NullableTypeStyle)
            {
                innerBody.Add
                    (new JST.IfStatement
                         (JST.Expression.IsNull(obj), new JST.Statements(new JST.ReturnStatement(new JST.NumericLiteral(0)))));
                innerBody.Add
                    (new JST.ReturnStatement
                         (JST.Expression.DotCall
                              (TypeCompEnv.ResolveType(TypeCompEnv.TypeBoundArguments[0], TypePhase.Slots),
                               Constants.TypeHash,
                               obj)));
            }
            else if (s is CST.StructTypeStyle)
            {
                var hashId = innerNameSupply.GenSym();
                innerBody.Add(JST.Statement.Var(hashId, new JST.NumericLiteral(0)));
                var hash = hashId.ToE();
                foreach (var fieldDef in Parent.Fields.Where(f => !f.IsStatic))
                {
                    innerBody.Add
                        (JST.Statement.Assignment
                             (hash,
                              new JST.BinaryExpression
                                  (new JST.BinaryExpression(hash, JST.BinaryOp.LeftShift, new JST.NumericLiteral(3)),
                                   JST.BinaryOp.BitwiseOR,
                                   new JST.BinaryExpression
                                       (hash, JST.BinaryOp.UnsignedRightShift, new JST.NumericLiteral(28)))));
                    var fieldRef = new CST.FieldRef(TypeCompEnv.TypeRef, fieldDef.FieldSignature);
                    var field = Env.JSTHelpers.ResolveInstanceField(TypeCompEnv, obj, fieldRef);
                    innerBody.Add
                        (JST.Statement.Assignment
                             (hash,
                              new JST.BinaryExpression
                                  (hash,
                                   JST.BinaryOp.BitwiseXOR,
                                   JST.Expression.DotCall
                                       (TypeCompEnv.ResolveType(fieldDef.FieldType, TypePhase.Slots),
                                        Constants.TypeHash,
                                        field))));
                }
                innerBody.Add(new JST.ReturnStatement(hash));
            }
            else if (s is CST.ObjectTypeStyle)
            {
                // NOTE: CLR Bizzarism: IEquatable<T> does not provide a GetHashCode, thus a
                //       default EqualityComparer<T> when T has IEquatable<T> will use the IEquatable
                //       Equals but the Object GetHashCode. Go figure.
                innerBody.Add
                    (new JST.IfStatement
                         (JST.Expression.IsNull(obj), new JST.Statements(new JST.ReturnStatement(new JST.NumericLiteral(0)))));
                var getHashCodeRef = new CST.MethodRef
                    (Env.Global.ObjectRef,
                     "GetHashCode",
                     false,
                     null,
                     new Seq<CST.TypeRef> { Env.Global.ObjectRef },
                     Env.Global.Int32Ref);
                var call = Env.JSTHelpers.DefaultVirtualMethodCallExpression
                    (TypeCompEnv, innerNameSupply, innerBody, getHashCodeRef, new Seq<JST.Expression> { obj });
                innerBody.Add(new JST.ReturnStatement(call));
            }
            else
                // Default is ok
                return;

            body.Add
                (JST.Statement.DotAssignment
                     (lhs, Constants.TypeHash, new JST.FunctionExpression(parameters, new JST.Statements(innerBody))));
        }