public InvocationTypeInferenceRules() : base(CompilerContext.Current)
        {
            var Array_EnumerableConstructor            = Map(Methods.Of <IEnumerable, Array>(Builtins.array));
            var Array_TypedEnumerableConstructor       = Map(Methods.Of <Type, IEnumerable, Array>(Builtins.array));
            var MultiDimensionalArray_TypedConstructor = Map(Methods.Of <Type, int[], Array>(Builtins.matrix));

            RegisterTypeInferenceRuleFor(
                MultiDimensionalArray_TypedConstructor,
                (invocation, method) =>
            {
                IType type = TypeSystemServices.GetReferencedType(invocation.Arguments[0]);
                if (type == null)
                {
                    return(null);
                }
                return(type.MakeArrayType(invocation.Arguments.Count - 1));
            });

            RegisterTypeInferenceRuleFor(
                Array_EnumerableConstructor,
                (invocation, method) =>
            {
                IType enumeratorItemType = TypeSystemServices.GetEnumeratorItemType(TypeSystemServices.GetExpressionType(invocation.Arguments[0]));
                if (TypeSystemServices.ObjectType == enumeratorItemType)
                {
                    return(null);
                }

                invocation.Target.Entity  = Array_TypedEnumerableConstructor;
                invocation.ExpressionType = Array_TypedEnumerableConstructor.ReturnType;
                invocation.Arguments.Insert(0, CodeBuilder.CreateReference(enumeratorItemType));
                return(enumeratorItemType.MakeArrayType(1));
            });
        }
示例#2
0
        override public void LeaveForStatement(ForStatement node)
        {
            IType enumeratorType               = GetExpressionType(node.Iterator);
            IType enumeratorItemType           = TypeSystemServices.GetEnumeratorItemType(enumeratorType);
            DeclarationCollection declarations = node.Declarations;
            Block body = new Block(node.LexicalInfo);

            InternalLocal iterator = CodeBuilder.DeclareLocal(
                _current,
                "___iterator" + _context.AllocIndex(),
                TypeSystemServices.IEnumeratorType);

            if (TypeSystemServices.IEnumeratorType.IsAssignableFrom(enumeratorType))
            {
                body.Add(
                    CodeBuilder.CreateAssignment(
                        CodeBuilder.CreateReference(iterator),
                        node.Iterator));
            }
            else
            {
                // ___iterator = <node.Iterator>.GetEnumerator()
                body.Add(
                    CodeBuilder.CreateAssignment(
                        CodeBuilder.CreateReference(iterator),
                        CodeBuilder.CreateMethodInvocation(
                            node.Iterator,
                            IEnumerable_GetEnumerator)));
            }

            // while __iterator.MoveNext():
            WhileStatement ws = new WhileStatement(node.LexicalInfo);

            ws.Condition = CodeBuilder.CreateMethodInvocation(
                CodeBuilder.CreateReference(iterator),
                IEnumerator_MoveNext);

            Expression current = CodeBuilder.CreateMethodInvocation(
                CodeBuilder.CreateReference(iterator),
                IEnumerator_get_Current);

            if (1 == declarations.Count)
            {
                //	item = __iterator.Current
                ws.Block.Add(
                    CodeBuilder.CreateAssignment(
                        CodeBuilder.CreateReference((InternalLocal)declarations[0].Entity),
                        current));
            }
            else
            {
                UnpackExpression(ws.Block,
                                 CodeBuilder.CreateCast(
                                     enumeratorItemType,
                                     current),
                                 node.Declarations);
            }

            ws.Block.Add(node.Block);

            body.Add(ws);

            ReplaceCurrentNode(body);
        }