public void DoEmitPartialApplicationCode(CompilerTarget target) { var argv = AstPartiallyApplicable.PreprocessPartialApplicationArguments( Subject.Singleton().Append(Arguments)); var ctorArgc = this.EmitConstructorArguments(target, argv); target.EmitConstant(Position, (int) Call); target.EmitConstant(Position, Id); target.EmitCommandCall(Position, ctorArgc + 2, Engine.PartialMemberCallAlias); }
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 }
public void DoEmitPartialApplicationCode(CompilerTarget target) { var argv = AstPartiallyApplicable.PreprocessPartialApplicationArguments(Arguments.ToList()); var ctorArgc = this.EmitConstructorArguments(target, argv); var constType = _typeExpr as AstConstantTypeExpression; if (constType != null) target.EmitConstant(Position, constType.TypeExpression); else _typeExpr.EmitValueCode(target); target.EmitCommandCall(Position, ctorArgc + 1, Engine.PartialConstructionAlias); }
public void DoEmitPartialApplicationCode(CompilerTarget target) { var argv = AstPartiallyApplicable.PreprocessPartialApplicationArguments(Subject.Singleton()); var ctorArgc = this.EmitConstructorArguments(target, argv); var constType = Type as AstConstantTypeExpression; if (constType != null) target.EmitConstant(Position, constType.TypeExpression); else Type.EmitValueCode(target); target.EmitCommandCall(Position, ctorArgc + 1, Engine.PartialTypeCastAlias); }
public void DoEmitPartialApplicationCode(CompilerTarget target) { var argv = AstPartiallyApplicable.PreprocessPartialApplicationArguments(Arguments); var ctorArgc = this.EmitConstructorArguments(target, argv); var constTypeExpr = TypeExpr as AstConstantTypeExpression; if (constTypeExpr != null) target.EmitConstant(constTypeExpr.Position, constTypeExpr.TypeExpression); else TypeExpr.EmitValueCode(target); target.EmitConstant(Position, (int) Call); target.EmitConstant(Position, _memberId); target.EmitCommandCall(Position, ctorArgc + 3, Engine.PartialStaticCallAlias); }
public void DoEmitPartialApplicationCode(CompilerTarget target) { if (Conditions.Count == 0) { this.ConstFunc(!ShortcircuitValue).EmitValueCode(target); return; } //only the very last condition may be a placeholder for (var node = Conditions.First; node != null; node = node.Next) { var isPlaceholder = node.Value.IsPlaceholder(); if (node.Next == null) { if (!isPlaceholder) { //there is no placeholder at all, wrap expression in const Debug.Assert(Conditions.All(e => !e.IsPlaceholder())); DoEmitCode(target,StackSemantics.Value); target.EmitCommandCall(Position, 1, Const.Alias); return; } } else { if (isPlaceholder) { _reportInvalidPlaceholders(target); return; } } } //We have expression of the form `e1 and e2 and e3 and ... and ?i` var placeholder = (AstPlaceholder) Conditions.Last.Value; AstPlaceholder.DeterminePlaceholderIndices(placeholder.Singleton()); // compile the following code: `if(e1 and e2 and e3) id(?) else const(false)` var constExpr = CreatePrefix(Position, Conditions.Take(Conditions.Count - 1)); //var identityFunc = new AstGetSetSymbol(File, Line, Column, PCall.Get, Commands.Core.Id.Alias, SymbolInterpretations.Command); //identityFunc.Arguments.Add(new AstPlaceholder(File, Line, Column, placeholder.Index)); var identityFunc = new AstTypecast(File, Line, Column, placeholder.GetCopy(), new AstConstantTypeExpression(File, Line, Column, PType.Bool.ToString())); var conditional = new AstConditionalExpression(File, Line, Column, constExpr, ShortcircuitValue) { IfExpression = identityFunc, ElseExpression = this.ConstFunc(ShortcircuitValue) }; conditional.EmitValueCode(target); }
public void DoEmitPartialApplicationCode(CompilerTarget target) { AstPlaceholder.DeterminePlaceholderIndices(Expressions.OfType<AstPlaceholder>()); var count = Expressions.Count; if (count == 0) { this.ConstFunc(null).EmitValueCode(target); return; } //only the very last condition may be a placeholder for (var i = 0; i < count; i++) { var value = Expressions[i]; var isPlaceholder = value.IsPlaceholder(); if (i == count - 1) { if (!isPlaceholder) { //there is no placeholder at all, wrap expression in const Debug.Assert(Expressions.All(e => !e.IsPlaceholder())); DoEmitCode(target,StackSemantics.Value); target.EmitCommandCall(Position, 1, Const.Alias); return; } } else { if (isPlaceholder) { _reportInvalidPlaceholders(target); return; } } } if (count == 0) { this.ConstFunc().EmitValueCode(target); } else if (count == 1) { Debug.Assert(Expressions[0].IsPlaceholder(), "Singleton ??-chain expected to consist of placeholder."); var placeholder = (AstPlaceholder) Expressions[0]; placeholder.IdFunc().EmitValueCode(target); } else { Debug.Assert(Expressions[count - 1].IsPlaceholder(), "Last expression in ??-chain expected to be placeholder."); var placeholder = (AstPlaceholder) Expressions[count - 1]; var prefix = new AstCoalescence(File, Line, Column); prefix.Expressions.AddRange(Expressions.Take(count - 1)); //check for null (keep a copy of prefix on stack) var constLabel = _generateEndLabel(); var endLabel = _generateEndLabel(); prefix._emitCode(target, constLabel, StackSemantics.Value); target.EmitDuplicate(Position); target.Emit(Position,OpCode.check_null); target.EmitJumpIfFalse(Position, constLabel); //prefix is null, identity function target.EmitPop(Position); placeholder.IdFunc().EmitValueCode(target); target.EmitJump(Position, endLabel); //prefix is not null, const function target.EmitLabel(Position, constLabel); target.EmitCommandCall(Position, 1, Const.Alias); target.EmitLabel(Position, endLabel); } }