Example #1
0
        protected override Type resolveExpressionType(Context ctx, bool mustReturn = true)
        {
            var leftType = LeftOperand.GetExpressionType(ctx);
            var rightType = RightOperand.GetExpressionType(ctx);

            var result = resolveOperatorType(ctx, leftType, rightType);
            if (result != null)
                return result;

            if (IsNumericOperator)
            {
                if (leftType.IsNumericType() && rightType.IsNumericType())
                    return resolveNumericType(ctx);
            }

            if (OverloadedMethodName != null)
            {
                try
                {
                    m_OverloadedMethod = ctx.ResolveMethod(leftType, OverloadedMethodName, new[] { leftType, rightType });

                    // cannot be generic
                    if (m_OverloadedMethod != null)
                        return m_OverloadedMethod.ReturnType;
                }
                catch { }
            }

            Error(this, CompilerMessages.OperatorBinaryTypesMismatch, OperatorRepresentation, leftType, rightType);
            return null;
        }
Example #2
0
        /// <summary>
        /// Resolves the method as a global function, imported property or a local variable with a delegate.
        /// </summary>
        private void resolveGetIdentifier(Context ctx, GetIdentifierNode node)
        {
            var nameInfo = ctx.Scope.FindLocal(node.Identifier);
            if (nameInfo != null)
            {
                resolveExpression(ctx, node);
                return;
            }

            try
            {
                _Method = ctx.ResolveMethod(
                    ctx.MainType.TypeInfo,
                    node.Identifier,
                    _ArgTypes,
                    resolver: (idx, types) => ctx.ResolveLambda(Arguments[idx] as LambdaNode, types)
                );

                if (_Method == null)
                    throw new KeyNotFoundException();

                if(_ArgTypes.Length == 0 && node.Identifier.IsAnyOf(EntityNames.RunMethodName, EntityNames.EntryPointMethodName))
                    error(CompilerMessages.ReservedFunctionInvocation, node.Identifier);
            }
            catch (KeyNotFoundException)
            {
                error(CompilerMessages.FunctionNotFound, node.Identifier);
            }
            catch (AmbiguousMatchException)
            {
                error(CompilerMessages.FunctionInvocationAmbiguous, node.Identifier);
            }
        }
Example #3
0
        /// <summary>
        /// Resolves the method if the expression was a member getter (obj.field or type::field).
        /// </summary>
        private void resolveGetMember(Context ctx, GetMemberNode node)
        {
            _InvocationSource = node.Expression;
            var type = _InvocationSource != null
                ? _InvocationSource.Resolve(ctx)
                : ctx.ResolveType(node.StaticType);

            checkTypeInSafeMode(ctx, type);

            if (node.TypeHints != null && node.TypeHints.Count > 0)
                _TypeHints = node.TypeHints.Select(x => ctx.ResolveType(x, true)).ToArray();

            try
            {
                // resolve a normal method
                try
                {
                    _Method = ctx.ResolveMethod(
                        type,
                        node.MemberName,
                        _ArgTypes,
                        _TypeHints,
                        (idx, types) => ctx.ResolveLambda(Arguments[idx] as LambdaNode, types)
                    );

                    if (_Method.IsStatic)
                        _InvocationSource = null;

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

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

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

                Arguments = (Arguments[0] is UnitNode)
                    ? new List<NodeBase> {_InvocationSource}
                    : new[] {_InvocationSource}.Union(Arguments).ToList();

                var oldArgTypes = _ArgTypes;
                _ArgTypes = Arguments.Select(a => a.Resolve(ctx)).ToArray();
                _InvocationSource = null;

                try
                {
                    // resolve a local function that is implicitly used as an extension method
                    _Method = ctx.ResolveMethod(
                        ctx.MainType.TypeInfo,
                        node.MemberName,
                        _ArgTypes,
                        resolver: (idx, types) => ctx.ResolveLambda(Arguments[idx] as LambdaNode, types)
                    );

                    return;
                }
                catch (KeyNotFoundException) { }

                // resolve a declared extension method
                // most time-consuming operation, therefore is last checked
                try
                {
                    if(!ctx.Options.AllowExtensionMethods)
                        throw new KeyNotFoundException();

                    _Method = ctx.ResolveExtensionMethod(
                        type,
                        node.MemberName,
                        oldArgTypes,
                        _TypeHints,
                        (idx, types) => ctx.ResolveLambda(Arguments[idx] as LambdaNode, types)
                    );
                }
                catch (KeyNotFoundException)
                {
                    var msg = node.StaticType != null
                        ? CompilerMessages.TypeStaticMethodNotFound
                        : CompilerMessages.TypeMethodNotFound;

                    error(msg, type, node.MemberName);
                }
            }
            catch (AmbiguousMatchException)
            {
                error(CompilerMessages.TypeMethodInvocationAmbiguous, type, node.MemberName);
            }
        }
Example #4
0
        private void castDelegate(Context ctx, Type from, Type to)
        {
            var gen = ctx.CurrentILGenerator;

            var toCtor = ctx.ResolveConstructor(to, new[] {typeof (object), typeof (IntPtr)});
            var fromMethod = ctx.ResolveMethod(from, "Invoke");
            var toMethod = ctx.ResolveMethod(to, "Invoke");

            var fromArgs = fromMethod.ArgumentTypes;
            var toArgs = toMethod.ArgumentTypes;

            if(fromArgs.Length != toArgs.Length || toArgs.Select((ta, id) => !ta.IsExtendablyAssignableFrom(fromArgs[id], true)).Any(x => x))
                Error(CompilerMessages.CastDelegateArgTypesMismatch, from, to);

            if(!toMethod.ReturnType.IsExtendablyAssignableFrom(fromMethod.ReturnType, true))
                Error(CompilerMessages.CastDelegateReturnTypesMismatch, from, to);

            if (fromMethod.IsStatic)
                gen.EmitNull();
            else
                Expression.Compile(ctx, true);

            if (from.IsGenericType && to.IsGenericType && from.GetGenericTypeDefinition() == to.GetGenericTypeDefinition())
                return;

            gen.EmitLoadFunctionPointer(fromMethod.MethodInfo);
            gen.EmitCreateObject(toCtor.ConstructorInfo);
        }
Example #5
0
        /// <summary>
        /// Resolves a method from the expression, considering it an instance of a delegate type.
        /// </summary>
        private void resolveExpression(Context ctx, NodeBase node)
        {
            var exprType = node.Resolve(ctx);
            if (!exprType.IsCallableType())
                error(CompilerMessages.TypeNotCallable, exprType);

            try
            {
                // argtypes are required for partial application
                _Method = ctx.ResolveMethod(exprType, "Invoke", _ArgTypes);
            }
            catch (KeyNotFoundException)
            {
                // delegate argument types are mismatched:
                // infer whatever method there is and detect actual error
                _Method = ctx.ResolveMethod(exprType, "Invoke");

                var argTypes = _Method.ArgumentTypes;
                if (argTypes.Length != _ArgTypes.Length)
                    error(CompilerMessages.DelegateArgumentsCountMismatch, exprType, argTypes.Length, _ArgTypes.Length);

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

            _InvocationSource = node;
        }
Example #6
0
        protected override Type resolve(Context ctx, bool mustReturn)
        {
            var type = Operand.Resolve(ctx);

            var result = resolveOperatorType(ctx);
            if (result != null)
                return result;

            if (OverloadedMethodName != null)
            {
                try
                {
                    _OverloadedMethod = ctx.ResolveMethod(type, OverloadedMethodName, new[] { type });

                    // cannot be generic
                    if (_OverloadedMethod != null)
                        return _OverloadedMethod.ReturnType;
                }
                catch { }
            }

            error(CompilerMessages.OperatorUnaryTypeMismatch, OperatorRepresentation, type);
            return null;
        }
Example #7
0
        /// <summary>
        /// Emits code for equality and inequality comparison.
        /// </summary>
        private void compileEquality(Context ctx, Type left, Type right)
        {
            var gen = ctx.CurrentILGenerator;

            // compare two strings
            if (left == typeof (string) && right == typeof (string))
            {
                LeftOperand.Compile(ctx, true);
                RightOperand.Compile(ctx, true);

                var method = typeof (string).GetMethod("Equals", new[] {typeof (string), typeof (string)});
                gen.EmitCall(method);

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

                return;
            }

            // compare two numerics
            if (left.IsNumericType() && right.IsNumericType())
            {
                loadAndConvertNumerics(ctx);
                gen.EmitCompareEqual();

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

                return;
            }

            // compare nullable against another nullable, it's base type or null
            if (left.IsNullableType())
            {
                if(left == right || Nullable.GetUnderlyingType(left) == right)
                    compileNullable(ctx, LeftOperand, RightOperand);
                else if(right == typeof(NullType))
                    compileHasValue(ctx, LeftOperand);

                return;
            }

            if (right.IsNullableType())
            {
                if (Nullable.GetUnderlyingType(right) == left)
                    compileNullable(ctx, RightOperand, LeftOperand);
                else if (left == typeof(NullType))
                    compileHasValue(ctx, RightOperand);

                return;
            }

            // compare a reftype against a null
            if (left == typeof(NullType) || right == typeof(NullType))
            {
                LeftOperand.Compile(ctx, true);
                RightOperand.Compile(ctx, true);
                gen.EmitCompareEqual();

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

                return;
            }

            if (left is TypeBuilder && left == right)
            {
                var equals = ctx.ResolveMethod(left, "Equals", new [] { typeof (object) });

                LeftOperand.Compile(ctx, true);
                RightOperand.Compile(ctx, true);

                gen.EmitCall(equals.MethodInfo);

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

                return;
            }
        }
Example #8
0
        protected override Type resolve(Context ctx, bool mustReturn)
        {
            var leftType = LeftOperand.Resolve(ctx);
            var rightType = RightOperand.Resolve(ctx);

            var result = resolveOperatorType(ctx, leftType, rightType);
            if (result != null)
                return result;

            if (OverloadedMethodName != null)
            {
                try
                {
                    _OverloadedMethod = ctx.ResolveMethod(leftType, OverloadedMethodName, new[] { leftType, rightType });
                }
                catch
                {
                    try
                    {
                        _OverloadedMethod = ctx.ResolveMethod(rightType, OverloadedMethodName, new[] { leftType, rightType });
                    }
                    catch { }
                }

                // cannot be generic
                if (_OverloadedMethod != null)
                    return _OverloadedMethod.ReturnType;
            }

            if (IsNumericOperator)
            {
                if (leftType.IsNullableType() || rightType.IsNullableType())
                {
                    var leftNullable = leftType.IsNullableType() ? leftType.GetGenericArguments()[0] : leftType;
                    var rightNullable = rightType.IsNullableType() ? rightType.GetGenericArguments()[0] : rightType;

                    var commonNumericType = TypeExtensions.GetNumericOperationType(leftNullable, rightNullable);
                    if (commonNumericType == null)
                        error(CompilerMessages.OperatorTypesSignednessMismatch);

                    return typeof(Nullable<>).MakeGenericType(commonNumericType);
                }

                if (leftType.IsNumericType() && rightType.IsNumericType())
                {
                    var commonNumericType = TypeExtensions.GetNumericOperationType(leftType, rightType);
                    if (commonNumericType == null)
                        error(CompilerMessages.OperatorTypesSignednessMismatch);

                    return commonNumericType;
                }
            }

            error(this, CompilerMessages.OperatorBinaryTypesMismatch, OperatorRepresentation, leftType, rightType);
            return null;
        }
Example #9
0
        private void detectEnumerableType(Context ctx)
        {
            var seqType = IterableExpression.GetExpressionType(ctx);
            if (seqType.IsArray)
            {
                m_VariableType = seqType.GetElementType();
                return;
            }

            var ifaces = GenericHelper.GetInterfaces(seqType);
            if(!ifaces.Any(i => i == typeof(IEnumerable) || (i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable<>))))
                Error(IterableExpression, CompilerMessages.TypeNotIterable, seqType);

            var enumerator = ctx.ResolveMethod(seqType, "GetEnumerator");
            m_EnumeratorType = enumerator.ReturnType;
            m_CurrentProperty = ctx.ResolveProperty(m_EnumeratorType, "Current");

            m_VariableType = m_CurrentProperty.PropertyType;
        }
Example #10
0
        public override void ProcessClosures(Context ctx)
        {
            if(LeftOperand is LambdaNode)
                LeftOperand.ProcessClosures(ctx);

            if (RightOperand is LambdaNode)
                RightOperand.ProcessClosures(ctx);

            var leftType = LeftOperand.GetExpressionType(ctx);

            var rightGetter = RightOperand as GetMemberNode;
            if (!IsLeft && leftType.IsCallableType() && rightGetter != null)
            {
                if (rightGetter.TypeHints.IsEmpty())
                {
                    var returnType = ctx.ResolveMethod(leftType, "Invoke").ReturnType;
                    rightGetter.TypeHints = new List<TypeSignature> {TypeSignature.Parse(returnType.FullName)};
                }
            }

            var rightType = RightOperand.GetExpressionType(ctx);

            if (rightGetter != null)
                rightGetter.TypeHints.Clear();

            if (!IsLeft && leftType.IsCallableType() && rightType.IsCallableType())
            {
                if (!ctx.CanCombineDelegates(leftType, rightType))
                    Error(Translations.CompilerMessages.DelegatesNotCombinable, leftType, rightType);

                var argTypes = ctx.WrapDelegate(leftType).ArgumentTypes;
                var argGetters = argTypes.Select((a, id) => Expr.GetArg(id)).Cast<NodeBase>().ToArray();

                if (LeftOperand is GetMemberNode)
                    (LeftOperand as GetMemberNode).TypeHints.Clear();

                _Method = ctx.CurrentScope.CreateClosureMethod(ctx, argTypes, ctx.WrapDelegate(rightType).ReturnType);
                _Method.Body =
                    Expr.Block(
                        Expr.Invoke(
                            RightOperand,
                            Expr.Invoke(
                                LeftOperand,
                                argGetters
                            )
                        )
                    );

                var methodBackup = ctx.CurrentMethod;
                ctx.CurrentMethod = _Method;

                var scope = _Method.Scope;
                scope.InitializeScope(ctx);

                _Method.Body.ProcessClosures(ctx);
                _Method.PrepareSelf();

                scope.FinalizeScope(ctx);

                ctx.CurrentMethod = methodBackup;
            }
        }
Example #11
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);
            }
        }
Example #12
0
        private void resolveGetIdentifier(Context ctx, GetIdentifierNode node)
        {
            var nameInfo = ctx.CurrentScope.FindName(node.Identifier);
            if (nameInfo != null)
            {
                resolveExpression(ctx, node);
                return;
            }

            try
            {
                m_Method = ctx.ResolveMethod(ctx.MainType.TypeInfo, node.Identifier, m_ArgTypes);
                if (m_Method == null)
                    throw new KeyNotFoundException();

                if(m_ArgTypes.Length == 0 && EnumerableExtensions.IsAnyOf(node.Identifier, EntityNames.RunMethodName, EntityNames.EntryPointMethodName))
                    Error(CompilerMessages.ReservedFunctionInvocation, node.Identifier);
            }
            catch (KeyNotFoundException)
            {
                Error(CompilerMessages.FunctionNotFound, node.Identifier);
            }
            catch (AmbiguousMatchException)
            {
                Error(CompilerMessages.FunctionInvocationAmbiguous, node.Identifier);
            }
        }
Example #13
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;
        }
Example #14
0
        /// <summary>
        /// Emits code for equality and inequality comparison.
        /// </summary>
        private void emitEqualityComparison(Context ctx, Type left, Type right)
        {
            var gen = ctx.CurrentMethod.Generator;

            // compare two strings
            if (left == right && left == typeof (string))
            {
                LeftOperand.Emit(ctx, true);
                RightOperand.Emit(ctx, true);

                var method = typeof (string).GetMethod("Equals", new[] {typeof (string), typeof (string)});
                gen.EmitCall(method);

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

                return;
            }

            // compare primitive types
            if ((left.IsNumericType() && right.IsNumericType()) || (left == right && left == typeof(bool)))
            {
                if (left == typeof (bool))
                {
                    LeftOperand.Emit(ctx, true);
                    RightOperand.Emit(ctx, true);
                }
                else
                {
                    loadAndConvertNumerics(ctx);
                }

                gen.EmitCompareEqual();

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

                return;
            }

            // compare nullable against another nullable, it's base type or null
            if (left.IsNullableType())
            {
                if(left == right || Nullable.GetUnderlyingType(left) == right)
                    emitNullableComparison(ctx, LeftOperand, RightOperand);
                else if(right == typeof(NullType))
                    emitHasValueCheck(ctx, LeftOperand);

                return;
            }

            if (right.IsNullableType())
            {
                if (Nullable.GetUnderlyingType(right) == left)
                    emitNullableComparison(ctx, RightOperand, LeftOperand);
                else if (left == typeof(NullType))
                    emitHasValueCheck(ctx, RightOperand);

                return;
            }

            // compare a reftype against a null
            if (left == typeof(NullType) || right == typeof(NullType))
            {
                LeftOperand.Emit(ctx, true);
                RightOperand.Emit(ctx, true);
                gen.EmitCompareEqual();

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

                return;
            }

            if (left is TypeBuilder && left == right)
            {
                var equals = ctx.ResolveMethod(left, "Equals", new [] { typeof (object) });

                LeftOperand.Emit(ctx, true);
                RightOperand.Emit(ctx, true);

                gen.EmitCall(equals.MethodInfo);

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

                return;
            }

            throw new ArgumentException("Unknown types to compare!");
        }