/// <summary>
        /// Emits code for comparing a nullable 
        /// </summary>
        private void compileNullable(Context ctx, NodeBase nullValue, NodeBase otherValue)
        {
            var gen = ctx.CurrentILGenerator;

            var nullType = nullValue.GetExpressionType(ctx);
            var otherType = otherValue.GetExpressionType(ctx);
            var otherNull = otherType.IsNullableType();

            var getValOrDefault = nullType.GetMethod("GetValueOrDefault", Type.EmptyTypes);
            var hasValueGetter = nullType.GetProperty("HasValue").GetGetMethod();

            var falseLabel = gen.DefineLabel();
            var endLabel = gen.DefineLabel();

            LocalName nullVar, otherVar = null;
            nullVar = ctx.CurrentScope.DeclareImplicitName(ctx, nullType, true);
            if (otherNull)
                otherVar = ctx.CurrentScope.DeclareImplicitName(ctx, otherType, true);
            //			if (otherNull)
            //			{
            //				otherVar = ctx.CurrentScope.DeclareImplicitName(ctx, otherType, true);
            //
            //				var code = Expr.Block(
            //					Expr.Let(nullVar, nullValue),
            //					Expr.Let(otherVar, otherValue),
            //					Expr.Binary(
            //						Kind == ComparisonOperatorKind.Equals ? BooleanOperatorKind.And : BooleanOperatorKind.Or,
            //						Expr.Compare(
            //							Kind,
            //							Expr.Invoke(Expr.GetIdentifier(nullVar), "GetValueOrDefault"),
            //							Expr.Invoke(Expr.GetIdentifier(otherVar), "GetValueOrDefault")
            //						),
            //						Expr.Compare(
            //							Kind,
            //							Expr.Invoke(Expr.GetIdentifier(nullVar), "get_HasValue"),
            //							Expr.Invoke(Expr.GetIdentifier(otherVar), "get_HasValue")
            //						)
            //					)
            //				);
            //
            //				code.Compile(ctx, true);
            //			}
            //			else
            //			{
            //				var code = Expr.Block(
            //					Expr.Let(nullVar, nullValue),
            //					Expr.Binary(
            //						Kind == ComparisonOperatorKind.Equals ? BooleanOperatorKind.And : BooleanOperatorKind.Or,
            //						Expr.Compare(
            //							Kind,
            //							Expr.Invoke(Expr.GetIdentifier(nullVar), "GetValueOrDefault"),
            //							Expr.Cast(otherValue, Nullable.GetUnderlyingType(nullType))
            //						),
            //						Expr.Invoke(Expr.GetIdentifier(nullVar), "get_HasValue")
            //					)
            //				);
            //
            //				code.Compile(ctx, true);
            //			}

            // $tmp = nullValue
            nullValue.Compile(ctx, true);
            gen.EmitSaveLocal(nullVar);

            if (otherNull)
            {
                // $tmp2 = otherValue
                otherValue.Compile(ctx, true);
                gen.EmitSaveLocal(otherVar);
            }

            // $tmp == $tmp2
            gen.EmitLoadLocal(nullVar, true);
            gen.EmitCall(getValOrDefault);

            if (otherNull)
            {
                gen.EmitLoadLocal(otherVar, true);
                gen.EmitCall(getValOrDefault);
            }
            else
            {
                otherValue.Compile(ctx, true);
            }

            gen.EmitBranchNotEquals(falseLabel);

            // otherwise, compare HasValues
            gen.EmitLoadLocal(nullVar, true);
            gen.EmitCall(hasValueGetter);

            if (otherNull)
            {
                gen.EmitLoadLocal(otherVar, true);
                gen.EmitCall(hasValueGetter);

                gen.EmitCompareEqual();
            }

            if(Kind == ComparisonOperatorKind.NotEquals)
                emitInversion(gen);

            gen.EmitJump(endLabel);

            gen.MarkLabel(falseLabel);
            gen.EmitConstant(false);

            gen.MarkLabel(endLabel);
            gen.EmitNop();
        }
Beispiel #2
0
        private void resolveGetMember(Context ctx, GetMemberNode node)
        {
            m_InvocationSource = node.Expression;
            var type = m_InvocationSource != null
                ? m_InvocationSource.GetExpressionType(ctx)
                : ctx.ResolveType(node.StaticType);

            SafeModeCheckType(ctx, type);

            if (node.TypeHints.Any())
                m_TypeHints = node.TypeHints.Select(x => x.FullSignature == "_" ? null : ctx.ResolveType(x)).ToArray();

            try
            {
                // resolve a normal method
                try
                {
                    m_Method = ctx.ResolveMethod(type, node.MemberName, m_ArgTypes, m_TypeHints);

                    if (m_Method.IsStatic)
                        m_InvocationSource = null;

                    return;
                }
                catch (KeyNotFoundException)
                {
                    if (m_InvocationSource == null)
                        throw;
                }

                // resolve a callable field
                try
                {
                    ctx.ResolveField(type, node.MemberName);
                    resolveExpression(ctx, node);
                    return;
                }
                catch (KeyNotFoundException) { }

                // resolve a callable field
                try
                {
                    ctx.ResolveProperty(type, node.MemberName);
                    resolveExpression(ctx, node);
                    return;
                }
                catch (KeyNotFoundException) { }

                // resolve a local function that is implicitly used as an extension method
                // move invocation source to arguments
                if (Arguments[0] is UnitNode)
                    Arguments[0] = m_InvocationSource;
                else
                    Arguments.Insert(0, m_InvocationSource);

                var oldArgTypes = m_ArgTypes;
                m_ArgTypes = Arguments.Select(a => a.GetExpressionType(ctx)).ToArray();
                m_InvocationSource = null;

                try
                {
                    m_Method = ctx.ResolveMethod(ctx.MainType.TypeInfo, node.MemberName, m_ArgTypes);
                }
                catch (KeyNotFoundException)
                {
                    // resolve a declared extension method
                    // most time-consuming operation, therefore is last checked
                    if(ctx.Options.AllowExtensionMethods)
                        m_Method = ctx.ResolveExtensionMethod(type, node.MemberName, oldArgTypes, m_TypeHints);
                }
            }
            catch (AmbiguousMatchException)
            {
                Error(CompilerMessages.TypeMethodInvocationAmbiguous, type, node.MemberName);
            }
            catch (KeyNotFoundException)
            {
                var msg = node.StaticType != null
                    ? CompilerMessages.TypeStaticMethodNotFound
                    : CompilerMessages.TypeMethodNotFound;

                Error(msg, type, node.MemberName);
            }
        }
        /// <summary>
        /// Checks if the nullable expression is null.
        /// </summary>
        private void compileHasValue(Context ctx, NodeBase nullValue)
        {
            var gen = ctx.CurrentILGenerator;
            var nullType = nullValue.GetExpressionType(ctx);
            var nullVar = ctx.CurrentScope.DeclareImplicitName(ctx, nullType, true);
            var hasValueGetter = nullType.GetProperty("HasValue").GetGetMethod();

            nullValue.Compile(ctx, true);
            gen.EmitSaveLocal(nullVar);

            gen.EmitLoadLocal(nullVar, true);
            gen.EmitCall(hasValueGetter);

            // sic! get_HasValue == true when value != null
            if(Kind == ComparisonOperatorKind.Equals)
                emitInversion(gen);
        }
Beispiel #4
0
        private void resolveExpression(Context ctx, NodeBase node)
        {
            var exprType = node.GetExpressionType(ctx);
            if (!exprType.IsCallableType())
                Error(CompilerMessages.TypeNotCallable, exprType);

            m_Method = ctx.ResolveMethod(exprType, "Invoke");
            var argTypes = m_Method.ArgumentTypes;
            if (argTypes.Length != m_ArgTypes.Length)
                Error(CompilerMessages.DelegateArgumentsCountMismatch, exprType, argTypes.Length, m_ArgTypes.Length);

            for (var idx = 0; idx < argTypes.Length; idx++)
            {
                var fromType = m_ArgTypes[idx];
                var toType = argTypes[idx];
                if (!toType.IsExtendablyAssignableFrom(fromType))
                    Error(Arguments[idx], CompilerMessages.ArgumentTypeMismatch, fromType, toType);
            }

            m_InvocationSource = node;
        }