protected override void DoEmitCode(CompilerTarget target, StackSemantics stackSemantics) { if (Elements.Count == 0) { target.Emit(Position,OpCode.newobj, 0, "Hash"); } else { foreach (var element in Elements) { if (element is AstConstant) throw new PrexoniteException( String.Concat( "Hashes are built from key-value pairs, not constants like ", element, ". [File: ", File, ", Line: ", Line, "]")); element.EmitCode(target,stackSemantics); } if(stackSemantics == StackSemantics.Effect) return; target.EmitStaticGetCall(Position, Elements.Count, "Hash", "Create", false); } }
protected override void DoEmitCode(CompilerTarget target, StackSemantics stackSemantics) { if(stackSemantics == StackSemantics.Effect) return; target.Emit(Position,OpCode.ldr_type, TypeExpression); }
protected override void DoEmitCode(CompilerTarget target, StackSemantics stackSemantics) { if(stackSemantics == StackSemantics.Effect) return; target.EmitNull(Position); }
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); }
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) { if(stackSemantics == StackSemantics.Value) throw new NotSupportedException("Using blocks do not produce values and can thus not be used as expressions."); if (_resourceExpression == null) throw new PrexoniteException("AstUsing requires Expression to be initialized."); var tryNode = new AstTryCatchFinally(Position, this); var vContainer = _block.CreateLabel("container"); target.Function.Variables.Add(vContainer); //Try block => Container = {Expression}; {Block}; var setCont = target.Factory.Call(Position, EntityRef.Variable.Local.Create(vContainer),PCall.Set); setCont.Arguments.Add(_resourceExpression); var getCont = target.Factory.Call(Position, EntityRef.Variable.Local.Create(vContainer)); var tryBlock = tryNode.TryBlock; tryBlock.Add(setCont); tryBlock.AddRange(_block); //Finally block => dispose( Container ); var dispose = target.Factory.Call(Position, EntityRef.Command.Create(Engine.DisposeAlias)); dispose.Arguments.Add(getCont); tryNode.FinallyBlock.Add(dispose); //Emit code! tryNode.EmitEffectCode(target); }
protected override void DoEmitCode(CompilerTarget target, StackSemantics stackSemantics) { if (Expression == null) throw new PrexoniteException("Expression must be assigned."); Expression.EmitValueCode(target); target.Emit(Position,OpCode.@throw); if (stackSemantics == StackSemantics.Value) target.Emit(Position,OpCode.ldc_null); }
protected override void DoEmitCode(CompilerTarget target, StackSemantics stackSemantics) { if (Key == null) throw new PrexoniteException("AstKeyValuePair.Key must be initialized."); if (Value == null) throw new ArgumentNullException("target"); var call = target.Factory.Call(Position, EntityRef.Command.Create(Engine.PairAlias)); call.Arguments.Add(Key); call.Arguments.Add(Value); call.EmitCode(target, stackSemantics); }
protected override void DoEmitCode(CompilerTarget target, StackSemantics stackSemantics) { if(stackSemantics == StackSemantics.Effect) return; if (Expression == null) throw new PrexoniteException("CreateCoroutine node requires an Expression."); Expression.EmitValueCode(target); foreach (var argument in _arguments) argument.EmitValueCode(target); target.Emit(Position,OpCode.newcor, _arguments.Count); }
protected override void DoEmitCode(CompilerTarget target, StackSemantics stackSemantics) { if (stackSemantics == StackSemantics.Effect) return; PFunction targetFunction; MetaEntry sharedNamesEntry; if (target.Loader.ParentApplication.TryGetFunction(_implementation.Id, _implementation.ModuleName, out targetFunction) && (!targetFunction.Meta.TryGetValue(PFunction.SharedNamesKey, out sharedNamesEntry) || !sharedNamesEntry.IsList || sharedNamesEntry.List.Length == 0)) target.Emit(Position,OpCode.ldr_func, _implementation.Id, target.ToInternalModule(_implementation.ModuleName)); else target.Emit(Position,OpCode.newclo, _implementation.Id, target.ToInternalModule(_implementation.ModuleName)); }
protected override void DoEmitCode(CompilerTarget target, StackSemantics stackSemantics) { if(stackSemantics == StackSemantics.Effect) return; Subject.EmitValueCode(target); var constType = Type as AstConstantTypeExpression; if (constType != null) target.Emit(Position,OpCode.cast_const, constType.TypeExpression); else { Type.EmitValueCode(target); target.Emit(Position,OpCode.cast_arg); } }
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); } }
protected override void DoEmitCode(CompilerTarget target, StackSemantics stackSemantics) { if(stackSemantics == StackSemantics.Value) throw new NotSupportedException("Return nodes cannot be used with value stack semantics. (They don't produce any values)"); var warned = false; if (target.Function.Meta[Coroutine.IsCoroutineKey].Switch) _warnInCoroutines(target, ref warned); if (Expression != null) { _OptimizeNode(target, ref Expression); if (ReturnVariant == ReturnVariant.Exit) { _emitTailCallExit(target); return; } } switch (ReturnVariant) { case ReturnVariant.Exit: target.Emit(Position,OpCode.ret_exit); break; case ReturnVariant.Set: if (Expression == null) throw new PrexoniteException("Return assignment requires an expression."); Expression.EmitValueCode(target); target.Emit(Position,OpCode.ret_set); break; case ReturnVariant.Continue: if (Expression != null) { Expression.EmitValueCode(target); target.Emit(Position,OpCode.ret_set); _warnInCoroutines(target, ref warned); } target.Emit(Position,OpCode.ret_continue); break; case ReturnVariant.Break: target.Emit(Position,OpCode.ret_break); break; } }
protected override void DoEmitCode(CompilerTarget target, StackSemantics stackSemantics) { if(stackSemantics == StackSemantics.Effect) return; if (Constant == null) target.EmitNull(Position); else switch (Type.GetTypeCode(Constant.GetType())) { case TypeCode.Boolean: target.EmitConstant(Position, (bool) Constant); break; case TypeCode.Int16: case TypeCode.Byte: case TypeCode.Int32: case TypeCode.UInt16: case TypeCode.UInt32: target.EmitConstant(Position, (int) Constant); break; case TypeCode.Single: case TypeCode.Double: target.EmitConstant(Position, (double) Constant); break; case TypeCode.String: target.EmitConstant(Position, (string) Constant); break; default: var moduleName = Constant as ModuleName; if (moduleName != null) { target.EmitConstant(Position, moduleName); } else { throw new PrexoniteException( "Prexonite does not support constants of type " + Constant.GetType().Name + "."); } break; } }
protected override void DoEmitCode(CompilerTarget target, StackSemantics stackSemantics) { //instantiate macro for the current target MacroSession session = null; try { //Acquire current macro session session = target.AcquireMacroSession(); //Expand macro var justEffect = stackSemantics == StackSemantics.Effect; var node = session.ExpandMacro(this, justEffect); //Emit generated code node.EmitCode(target, stackSemantics); } finally { if (session != null) target.ReleaseMacroSession(session); } }
protected abstract void EmitGetCode(CompilerTarget target, StackSemantics stackSemantics);
protected override void DoEmitCode(CompilerTarget target, StackSemantics semantics) { Expression.EmitCode(target, semantics); Action.EmitCode(target,StackSemantics.Effect); // At this point, the value of the expression remains on the stack. }
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, 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); } }
protected override void EmitGetCode(CompilerTarget target, StackSemantics stackSemantics) { target.Loader.ReportMessage(Message.Error(Resources.Parser_ExpectedEntityFoundNamespace, Position, MessageClasses.ExpectedEntityFoundNamespace)); if(stackSemantics == StackSemantics.Value) target.EmitNull(Position); }
protected override void DoEmitCode(CompilerTarget target, StackSemantics stackSemantics) { target.EmitLabel(Position, Label); }
protected override void DoEmitCode(CompilerTarget target, StackSemantics stackSemantics) { Subject.EmitValueCode(target); base.DoEmitCode(target, stackSemantics); }
protected override void DoEmitCode(CompilerTarget target, StackSemantics stackSemantics) { if(stackSemantics == StackSemantics.Value) throw new NotSupportedException("Try-catch-finally blocks cannot be used with value stack semantics (They don't produce values)"); var prefix = "try\\" + Guid.NewGuid().ToString("N") + "\\"; var beginTryLabel = prefix + "beginTry"; var beginFinallyLabel = prefix + "beginFinally"; var beginCatchLabel = prefix + "beginCatch"; var endTry = prefix + "endTry"; if (TryBlock.IsEmpty) if (FinallyBlock.IsEmpty) return; else { //The finally block is not protected // A trycatchfinally with just a finally block is equivalent to the contents of the finally block // " try {} finally { $code } " => " $code " FinallyBlock.EmitEffectCode(target); return; } //Emit try block target.EmitLabel(Position, beginTryLabel); target.Emit(Position,OpCode.@try); TryBlock.EmitEffectCode(target); //Emit finally block target.EmitLabel(FinallyBlock.Position, beginFinallyLabel); var beforeEmit = target.Code.Count; FinallyBlock.EmitEffectCode(target); if (FinallyBlock.Count > 0 && target.Code.Count == beforeEmit) target.Emit(FinallyBlock.Position, OpCode.nop); target.EmitLeave(FinallyBlock.Position, endTry); //Emit catch block target.EmitLabel(CatchBlock.Position, beginCatchLabel); var usesException = ExceptionVar != null; var justRethrow = CatchBlock.IsEmpty && !usesException; if (usesException) { //Assign exception ExceptionVar = _GetOptimizedNode(target, ExceptionVar) as AstGetSet ?? ExceptionVar; ExceptionVar.Arguments.Add(new AstGetException(File, Line, Column)); ExceptionVar.Call = PCall.Set; ExceptionVar.EmitEffectCode(target); } if (!justRethrow) { //Exception handled CatchBlock.EmitEffectCode(target); } else { //Exception not handled => rethrow. // * Rethrow is implemented in the runtime * //AstThrow th = new AstThrow(File, Line, Column); //th.Expression = new AstGetException(File, Line, Column); //th.EmitCode(target); } target.EmitLabel(Position, endTry); target.Emit(Position,OpCode.nop); var block = new TryCatchFinallyBlock( _getAddress(target, beginTryLabel), _getAddress(target, endTry)) { BeginFinally = (!FinallyBlock.IsEmpty ? _getAddress(target, beginFinallyLabel) : -1), BeginCatch = (!justRethrow ? _getAddress(target, beginCatchLabel) : -1), UsesException = usesException }; //Register try-catch-finally block target.Function.Meta.AddTo(TryCatchFinallyBlock.MetaKey, block); target.Function.InvalidateTryCatchFinallyBlocks(); }
protected override void DoEmitCode(CompilerTarget target, StackSemantics stackSemantics) { foreach (var expr in Arguments) expr.EmitCode(target,stackSemantics); if(stackSemantics == StackSemantics.Value) target.Emit(Position,OpCode.newtype, Arguments.Count, TypeId); }
protected override void EmitGetCode(CompilerTarget target, StackSemantics stackSemantics) { _reportUnresolved(target); target.EmitNull(Position); }
protected override void EmitGetCode(CompilerTarget target, StackSemantics stackSemantics) { target.EmitGetCall(Position, Arguments.Count, Id, stackSemantics == StackSemantics.Effect); }
protected override void EmitGetCode(CompilerTarget target, StackSemantics stackSemantics) { _throwSyntaxNotSupported(); }
protected override void EmitGetCode(CompilerTarget target, StackSemantics stackSemantics) { throw new NotSupportedException("Macro expansion requires a different mechanism. Use AstGetSet.EmitCode instead."); }
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) { if (Call == PCall.Get) { EmitArguments(target); EmitGetCode(target, stackSemantics); } else { EmitArguments(target, stackSemantics == StackSemantics.Value); EmitSetCode(target); } }