Example #1
0
        protected override void EmitGetCode(CompilerTarget target, StackSemantics stackSemantics)
        {
            var constType = TypeExpr as AstConstantTypeExpression;

            var justEffect = stackSemantics == StackSemantics.Effect;
            if (constType != null)
            {
                EmitArguments(target);
                target.EmitStaticGetCall(Position, Arguments.Count, constType.TypeExpression, _memberId, justEffect);
            }
            else
            {
                TypeExpr.EmitValueCode(target);
                target.EmitConstant(Position, _memberId);
                EmitArguments(target);
                target.EmitGetCall(Position, Arguments.Count + 1, PType.StaticCallFromStackId, justEffect);
            }
        }
Example #2
0
        protected override void DoEmitCode(CompilerTarget target, StackSemantics stackSemantics)
        {
            if(stackSemantics == StackSemantics.Value)
                throw new NotSupportedException("Foreach loops don't produce values and can thus not be emitted with value semantics.");

            if (!IsInitialized)
                throw new PrexoniteException("AstForeachLoop requires List and Element to be set.");

            //Optimize expression
            _OptimizeNode(target, ref List);

            //Create the enumerator variable
            var enumVar = Block.CreateLabel("enumerator");
            target.Function.Variables.Add(enumVar);

            //Create the element assignment statement
            var element = Element.GetCopy();
            AstExpr optElem;
            if (element.TryOptimize(target, out optElem))
            {
                element = optElem as AstGetSet;
                if (element == null)
                {
                    target.Loader.ReportMessage(Message.Error(Resources.AstForeachLoop_DoEmitCode_ElementTooComplicated,Position,MessageClasses.ForeachElementTooComplicated));
                    return;
                }
            }
            var ldEnumVar = target.Factory.Call(Position, EntityRef.Variable.Local.Create(enumVar));
            var getCurrent =
                new AstGetSetMemberAccess(File, Line, Column, ldEnumVar, "Current");
            element.Arguments.Add(getCurrent);
            element.Call = PCall.Set;

            //Actual Code Generation
            var moveNextAddr = -1;
            var getCurrentAddr = -1;
            var disposeAddr = -1;

            //Get the enumerator
            target.BeginBlock(Block);

            List.EmitValueCode(target);
            target.EmitGetCall(List.Position, 0, "GetEnumerator");
            var castAddr = target.Code.Count;
            target.Emit(List.Position, OpCode.cast_const, "Object(\"System.Collections.IEnumerator\")");
            target.EmitStoreLocal(List.Position, enumVar);

            //check whether an enhanced CIL implementation is possible
            bool emitHint;
            if (element.DefaultAdditionalArguments + element.Arguments.Count > 1)
                //has additional arguments
                emitHint = false;
            else
                emitHint = true;

            var @try = new AstTryCatchFinally(Position, Block);

            @try.TryBlock = new AstActionBlock
                (
                Position, @try,
                delegate
                    {
                        target.EmitJump(Position, Block.ContinueLabel);

                        //Assignment (begin)
                        target.EmitLabel(Position, Block.BeginLabel);
                        getCurrentAddr = target.Code.Count;
                        element.EmitEffectCode(target);

                        //Code block
                        Block.EmitEffectCode(target);

                        //Condition (continue)
                        target.EmitLabel(Position, Block.ContinueLabel);
                        moveNextAddr = target.Code.Count;
                        target.EmitLoadLocal(List.Position, enumVar);
                        target.EmitGetCall(List.Position, 0, "MoveNext");
                        target.EmitJumpIfTrue(Position, Block.BeginLabel);

                        //Break
                        target.EmitLabel(Position, Block.BreakLabel);
                    });
            @try.FinallyBlock = new AstActionBlock
                (
                Position, @try,
                delegate
                    {
                        disposeAddr = target.Code.Count;
                        target.EmitLoadLocal(List.Position, enumVar);
                        target.EmitCommandCall(List.Position, 1, Engine.DisposeAlias, true);
                    });
                

            @try.EmitEffectCode(target);

            target.EndBlock();

            if (getCurrentAddr < 0 || moveNextAddr < 0 || disposeAddr < 0)
                throw new PrexoniteException(
                    "Could not capture addresses within foreach construct for CIL compiler hint.");
            else if (emitHint)
            {
                var hint = new ForeachHint(enumVar, castAddr, getCurrentAddr, moveNextAddr,
                    disposeAddr);
                Cil.Compiler.AddCilHint(target, hint);

                Action<int, int> mkHook =
                    (index, original) =>
                        {
                            AddressChangeHook hook = null;
                            hook = new AddressChangeHook(
                                original,
                                newAddr =>
                                    {
                                        foreach (
                                            var hintEntry in target.Meta[Loader.CilHintsKey].List)
                                        {
                                            var entry = hintEntry.List;
                                            if (entry[0] == ForeachHint.Key &&
                                                entry[index].Text == original.ToString(CultureInfo.InvariantCulture))
                                            {
                                                entry[index] = newAddr.ToString(CultureInfo.InvariantCulture);
                                                // AddressChangeHook.ctor can be trusted not to call the closure.
                                                // ReSharper disable PossibleNullReferenceException
                                                // ReSharper disable AccessToModifiedClosure
                                                hook.InstructionIndex = newAddr;
                                                // ReSharper restore AccessToModifiedClosure
                                                // ReSharper restore PossibleNullReferenceException
                                                original = newAddr;
                                            }
                                        }
                                    });
                            target.AddressChangeHooks.Add(hook);
                        };

                mkHook(ForeachHint.CastAddressIndex + 1, castAddr);
                mkHook(ForeachHint.GetCurrentAddressIndex + 1, getCurrentAddr);
                mkHook(ForeachHint.MoveNextAddressIndex + 1, moveNextAddr);
                mkHook(ForeachHint.DisposeAddressIndex + 1, disposeAddr);
            } // else nothing
        }
Example #3
0
 protected override void EmitGetCode(CompilerTarget target, StackSemantics stackSemantics)
 {
     target.EmitGetCall(Position, Arguments.Count, Id, stackSemantics == StackSemantics.Effect);
 }
Example #4
0
        protected override void DoEmitCode(CompilerTarget target, StackSemantics stackSemantics)
        {
            var constType = _typeExpr as AstConstantTypeExpression;

            if (constType != null)
            {
                foreach (var arg in _arguments)
                    arg.EmitValueCode(target);
                target.Emit(Position,OpCode.newobj, _arguments.Count, constType.TypeExpression);
                if(stackSemantics == StackSemantics.Effect)
                    target.Emit(Position,Instruction.CreatePop());
            }
            else
            {
                //Load type and call construct on it
                _typeExpr.EmitValueCode(target);
                foreach (var arg in _arguments)
                    arg.EmitValueCode(target);
                var justEffect = stackSemantics == StackSemantics.Effect;
                target.EmitGetCall(Position, _arguments.Count, PType.ConstructFromStackId, justEffect);
            }
        }
Example #5
0
        /// <summary>
        ///     Emits code for the AstStringConcatenation node.
        /// </summary>
        /// <param name = "target">The target to which to write the code to.</param>
        /// <param name="stackSemantics">The stack semantics with which to emit code. </param>
        /// <remarks>
        ///     <para>
        ///         AstStringConcatenation tries to find the most efficient way to concatenate strings. StringBuilders are actually slower when concatenating only two arguments.
        ///     </para>
        ///     <para>
        ///         <list type = "table">
        ///             <listheader>
        ///                 <term>Arguments</term>
        ///                 <description>Emitted code</description>
        ///             </listheader>
        ///             <item>
        ///                 <term>0</term>
        ///                 <description><c><see cref = "OpCode.ldc_string">ldc.string</see> ""</c> (Empty string)</description>
        ///             </item>
        ///             <item>
        ///                 <term>1</term>
        ///                 <description>Just that argument and, unless it is a <see cref = "AstConstant">string constant</see>, a call to <c>ToString</c>.</description>
        ///             </item>
        ///             <item>
        ///                 <term>2</term>
        ///                 <description>Concatenation using the Addition (<c><see cref = "OpCode.add">add</see></c>) operator.</description>
        ///             </item>
        ///             <item>
        ///                 <term>n</term>
        ///                 <description>A call to the <c><see cref = "Prexonite.Engine.ConcatenateAlias">concat</see></c> command.</description>
        ///             </item>
        ///         </list>
        ///     </para>
        /// </remarks>
        protected override void DoEmitCode(CompilerTarget target, StackSemantics stackSemantics)
        {
            if (_arguments.Count > 2)
            {
                var call = _multiConcatPrototype.GetCopy();
                call.Arguments.AddRange(Arguments);
                call.EmitCode(target, stackSemantics);
            }
            else if (_arguments.Count >= 2)
            {
                var call = _simpleConcatPrototype.GetCopy();
                call.Arguments.AddRange(Arguments);
                call.EmitCode(target, stackSemantics);
            }
            else if (_arguments.Count == 1)
            {
                if (stackSemantics == StackSemantics.Value)
                {
                    _arguments[0].EmitValueCode(target);

                    AstConstant constant;
                    if ((constant = _arguments[0] as AstConstant) != null &&
                        !(constant.Constant is string))
                        target.EmitGetCall(Position, 1, "ToString");
                }
                else
                {
                    _arguments[0].EmitEffectCode(target);
                }
            }
            else if (_arguments.Count == 0)
            {
                if(stackSemantics == StackSemantics.Value)
                    target.EmitConstant(Position, "");
            }
        }