protected override void DoEmitCode(CompilerTarget target, StackSemantics stackSemantics) { var labelNs = @"Or\" + Guid.NewGuid().ToString("N"); var trueLabel = @"True\" + labelNs; var falseLabel = @"False\" + labelNs; var evalLabel = @"Eval\" + labelNs; EmitCode(target, trueLabel, falseLabel); if (stackSemantics == StackSemantics.Value) { target.EmitLabel(Position, falseLabel); target.EmitConstant(Position, false); target.EmitJump(Position, evalLabel); target.EmitLabel(Position, trueLabel); target.EmitConstant(Position, true); target.EmitLabel(Position, evalLabel); } else { Debug.Assert(stackSemantics == StackSemantics.Effect); target.EmitLabel(Position, falseLabel); target.EmitLabel(Position, trueLabel); } }
protected override void DoEmitCode(CompilerTarget target, StackSemantics stackSemantics) { //Jumps need special treatment for label resolution if (Instruction.Arguments == -1) { switch (Instruction.OpCode) { case OpCode.jump: target.EmitJump(Position, Instruction.Id); break; case OpCode.jump_t: target.EmitJumpIfTrue(Position, Instruction.Id); break; case OpCode.jump_f: target.EmitJumpIfFalse(Position, Instruction.Id); break; case OpCode.leave: target.EmitLeave(Position, Instruction.Id); break; default: goto emitNormally; } } else goto emitNormally; return; emitNormally: target.Emit(Position, Instruction); }
private void _emitRecursiveTailCall(CompilerTarget target, ArgumentsProxy symbolArgs) { var symbolParams = target.Function.Parameters; var nullNode = new AstNull(File, Line, Column); //copy parameters to temporary variables for (var i = 0; i < symbolParams.Count; i++) { if (i < symbolArgs.Count) symbolArgs[i].EmitValueCode(target); else nullNode.EmitValueCode(target); } //overwrite parameters for (var i = symbolParams.Count - 1; i >= 0; i--) { target.EmitStoreLocal(Position, symbolParams[i]); } target.EmitJump(Position, 0); }
protected override void DoEmitCode(CompilerTarget target, StackSemantics stackSemantics) { if(stackSemantics == StackSemantics.Value) throw new NotSupportedException("While loops do not produce values and can thus not be used as expressions."); if (!IsInitialized) throw new PrexoniteException("AstWhileLoop requires Condition to be set."); //Optimize unary not condition _OptimizeNode(target, ref Condition); // Invert condition when unary logical not AstIndirectCall unaryCond; while (Condition.IsCommandCall(Commands.Core.Operators.LogicalNot.DefaultAlias, out unaryCond)) { Condition = unaryCond.Arguments[0]; IsPositive = !IsPositive; } //Constant conditions var conditionIsConstant = false; if (Condition is AstConstant) { var constCond = (AstConstant) Condition; PValue condValue; if ( !constCond.ToPValue(target).TryConvertTo( target.Loader, PType.Bool, out condValue)) goto continueFull; else if ((bool) condValue.Value == IsPositive) conditionIsConstant = true; else { //Condition is always false if (!IsPrecondition) //If do-while, emit the body without loop code { target.BeginBlock(Block); Block.EmitEffectCode(target); target.EndBlock(); } return; } } continueFull: target.BeginBlock(Block); if (!Block.IsEmpty) //Body exists -> complete loop code? { if (conditionIsConstant) //Infinite, hopefully user managed, loop -> { target.EmitLabel(Position, Block.ContinueLabel); target.EmitLabel(Position, Block.BeginLabel); Block.EmitEffectCode(target); target.EmitJump(Position, Block.ContinueLabel); } else { if (IsPrecondition) target.EmitJump(Position, Block.ContinueLabel); target.EmitLabel(Position, Block.BeginLabel); Block.EmitEffectCode(target); _emitCondition(target); } } else //Body does not exist -> Condition loop { target.EmitLabel(Position, Block.BeginLabel); _emitCondition(target); } target.EmitLabel(Position, Block.BreakLabel); target.EndBlock(); }
protected override void DoEmitCode(CompilerTarget target, string trueLabel, string falseLabel) { var labelNs = @"Or\" + Guid.NewGuid().ToString("N"); var nextLabel = @"Next\" + labelNs; foreach (var expr in Conditions) { var and = expr as AstLogicalAnd; if (and != null) { and.EmitCode(target, trueLabel, nextLabel); //ResolveOperator pending jumps to Next target.EmitLabel(Position, nextLabel); target.FreeLabel(nextLabel); //Future references of to nextLabel will be resolved in the next iteration } else { expr.EmitValueCode(target); target.EmitJumpIfTrue(Position, trueLabel); } } target.EmitJump(Position, falseLabel); }
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 }
protected override void DoEmitCode(CompilerTarget target, StackSemantics stackSemantics) { //Optimize condition _OptimizeNode(target, ref Condition); // Invert condition when unary logical not AstIndirectCall unaryCond; while (Condition.IsCommandCall(Commands.Core.Operators.LogicalNot.DefaultAlias, out unaryCond)) { Condition = unaryCond.Arguments[0]; IsNegative = !IsNegative; } //Constant conditions if (Condition is AstConstant) { var constCond = (AstConstant) Condition; PValue condValue; if ( !constCond.ToPValue(target).TryConvertTo( target.Loader, PType.Bool, out condValue)) goto continueFull; else if (((bool) condValue.Value) ^ IsNegative) IfBlock.EmitEffectCode(target); else ElseBlock.EmitEffectCode(target); return; } //Conditions with empty blocks if (IfBlock.IsEmpty && ElseBlock.IsEmpty) { Condition.EmitEffectCode(target); return; } continueFull: ; //Switch If and Else block in case the if-block is empty if (IfBlock.IsEmpty) { IsNegative = !IsNegative; var tmp = IfBlock; IfBlock = ElseBlock; ElseBlock = tmp; } var elseLabel = "else\\" + _depth + "\\assembler"; var endLabel = "endif\\" + _depth + "\\assembler"; _depth++; //Emit var ifGoto = IfBlock.IsSingleStatement ? IfBlock[0] as AstExplicitGoTo : null; var elseGoto = ElseBlock.IsSingleStatement ? ElseBlock[0] as AstExplicitGoTo : null; ; var ifIsGoto = ifGoto != null; var elseIsGoto = elseGoto != null; if (ifIsGoto && elseIsGoto) { //only jumps AstLazyLogical.EmitJumpCondition( target, Condition, ifGoto.Destination, elseGoto.Destination, !IsNegative); } else if (ifIsGoto) { //if => jump / else => block AstLazyLogical.EmitJumpCondition(target, Condition, ifGoto.Destination, !IsNegative); ElseBlock.EmitEffectCode(target); } else if (elseIsGoto) { //if => block / else => jump AstLazyLogical.EmitJumpCondition( target, Condition, elseGoto.Destination, IsNegative); //inverted IfBlock.EmitEffectCode(target); } else { //if => block / else => block AstLazyLogical.EmitJumpCondition(target, Condition, elseLabel, IsNegative); IfBlock.EmitEffectCode(target); target.EmitJump(Position, endLabel); target.EmitLabel(Position, elseLabel); ElseBlock.EmitEffectCode(target); target.EmitLabel(Position, endLabel); } target.FreeLabel(elseLabel); target.FreeLabel(endLabel); }
protected override void DoEmitCode(CompilerTarget target, StackSemantics stackSemantics) { if(stackSemantics == StackSemantics.Value) throw new NotSupportedException("For loops don't produce values and can thus not be emitted with value semantics."); if (!IsInitialized) throw new PrexoniteException("AstForLoop requires Condition to be set."); //Optimize unary not condition var condition = Condition; _OptimizeNode(target, ref condition); // Invert condition when unary logical not AstIndirectCall unaryCond; while (Condition.IsCommandCall(Commands.Core.Operators.LogicalNot.DefaultAlias, out unaryCond)) { Condition = unaryCond.Arguments[0]; IsPositive = !IsPositive; } //Constant conditions var conditionIsConstant = false; var constCond = condition as AstConstant; if (constCond != null) { PValue condValue; if ( !constCond.ToPValue(target).TryConvertTo( target.Loader, PType.Bool, out condValue)) goto continueFull; else if ((bool) condValue.Value == IsPositive) conditionIsConstant = true; else { //Condition is always false return; } } continueFull: var conditionLabel = Block.CreateLabel("condition"); if (!Block.IsEmpty) //Body exists -> complete loop code? { if (conditionIsConstant) //Infinite, hopefully user managed, loop -> { /* {init} * begin: * {block} * continue: * {next} * jump -> begin */ target.BeginBlock(Initialize); Initialize.EmitValueCode(target); if (!IsPrecondition) //start with nextIteration target.EmitJump(Position, Block.ContinueLabel); target.EmitLabel(Position, Block.BeginLabel); target.BeginBlock(NextIteration); target.BeginBlock(Block); Block.EmitEffectCode(target); target.EndBlock(); target.EmitLabel(Position, Block.ContinueLabel); NextIteration.EmitValueCode(target); target.EndBlock(); target.EmitJump(Position, Block.BeginLabel); target.EndBlock(); } else //Variable condition and body -> full loop code { /* {init} * jump -> condition * begin: * {block} * continue: * {next} * condition: * {condition} * jump if true -> begin */ target.BeginBlock(Initialize); Initialize.EmitValueCode(target); target.BeginBlock(NextIteration); if (IsPrecondition) target.EmitJump(Position, conditionLabel); else target.EmitJump(Position, Block.ContinueLabel); target.EmitLabel(Position, Block.BeginLabel); target.BeginBlock(Block); Block.EmitEffectCode(target); target.EndBlock(); target.EmitLabel(Position, Block.ContinueLabel); NextIteration.EmitValueCode(target); target.EndBlock(); target.EmitLabel(Position, conditionLabel); AstLazyLogical.EmitJumpCondition( target, condition, Block.BeginLabel, IsPositive); target.EndBlock(); } } else //Body does not exist -> Condition loop { /* {init} * begin: * {cond} * jump if false -> break * continue: * {next} * jump -> begin */ target.BeginBlock(Block); Initialize.EmitValueCode(target); if (!IsPrecondition) target.EmitJump(Position, Block.ContinueLabel); target.EmitLabel(Position, Block.BeginLabel); AstLazyLogical.EmitJumpCondition(target, condition, Block.BreakLabel, !IsPositive); if (IsPrecondition) target.EmitLabel(Position, Block.ContinueLabel); NextIteration.EmitValueCode(target); target.EmitJump(Position, Block.BeginLabel); target.EndBlock(); } target.EmitLabel(Position, Block.BreakLabel); }
protected override void DoEmitCode(CompilerTarget target, StackSemantics stackSemantics) { target.EmitJump(Position, _destination); }
public void EmitCode(CompilerTarget target, string trueLabel, string falseLabel) { foreach (var condition in Conditions) { if (condition.CheckForPlaceholders()) { target.Loader.ReportMessage( Message.Error( Resources.AstLazyLogical_EmitCode_PureChainsExpected, Position, MessageClasses.OnlyLastOperandPartialInLazy)); target.EmitJump(Position, trueLabel); return; } } DoEmitCode(target, trueLabel, falseLabel); }
public static void EmitJumpCondition( CompilerTarget target, AstExpr cond, string targetLabel, string alternativeLabel, bool isPositive) { if (cond == null) throw new ArgumentNullException("cond", Resources.AstLazyLogical__Condition_must_not_be_null); if (target == null) throw new ArgumentNullException("target", Resources.AstNode_Compiler_target_must_not_be_null); if (String.IsNullOrEmpty(targetLabel)) throw new ArgumentException( Resources.AstLazyLogical__targetLabel_must_neither_be_null_nor_empty, "targetLabel"); if (String.IsNullOrEmpty(alternativeLabel)) throw new ArgumentException( Resources.AstLazyLogical_alternativeLabel_may_neither_be_null_nor_empty, "alternativeLabel"); var logical = cond as AstLazyLogical; if (!isPositive) { //Invert if needed var tmpLabel = alternativeLabel; alternativeLabel = targetLabel; targetLabel = tmpLabel; } if (logical != null) { logical.EmitCode(target, targetLabel, alternativeLabel); } else { cond.EmitValueCode(target); target.EmitJumpIfTrue(cond.Position, targetLabel); target.EmitJump(cond.Position, alternativeLabel); } }
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); } }
protected override void DoEmitCode(CompilerTarget target, StackSemantics stackSemantics) { //Optimize condition _OptimizeNode(target, ref Condition); _OptimizeNode(target, ref IfExpression); _OptimizeNode(target, ref ElseExpression); var elseLabel = "elsei\\" + _depth + "\\assembler"; var endLabel = "endifi\\" + _depth + "\\assembler"; _depth++; //Emit //if => block / else => block AstLazyLogical.EmitJumpCondition(target, Condition, elseLabel, IsNegative); IfExpression.EmitCode(target, stackSemantics); target.EmitJump(Position, endLabel); target.EmitLabel(Position, elseLabel); ElseExpression.EmitCode(target, stackSemantics); target.EmitLabel(Position, endLabel); target.FreeLabel(elseLabel); target.FreeLabel(endLabel); }